#함수 호출 (인자에 이름 붙여 함수 호출)
- 함수 호출 시 인자에 이름을 붙여서 호출 할 수 있다
- java에 정의된 함수일 경우 인자에 이름 붙여 호출은 불가(코틀린은 JDK 6과 호환되는데, 클래스 파일에 함수 파람 정보를 넣는것은 JAVA 8 이후 추가됨)
- 장점 : 함수 호출 코드를 명확하게 표시 할 수 있다 -> 가독성 UP
fun paramNameTest(str1: String, str2: String, str3: String) {...}
paramNameTest("11", "22", "33") //일반적 함수 호출
paramNameTest(str1 = "11", str2 = "22", str3 = "33") //인자에 이름 붙여 호출
#함수 호출 (디폴트 파람 값 추가)
- 함수 정의 시 파라미터에 대한 디폴트 값을 정의 할 수 있다 (함수 선언 쪽에)
- 그럴 경우 함수 호출 시 아래와 같이 파라미터를 생략 후 호출 할 수 있다
- 장점 : 오버로딩한 함수를 정의할 필요성이 줄어든다
fun paramNameTest(str1: String = "defaultStr1", str2: String= "defaultStr2", str3: String= "defaultStr3") {...}
paramNameTest("11", "22") //str3 생략
paramNameTest("11") //str2, str3 생략
paramNameTest("11", str3="33") //str2만 생략(중간에 낀 인자만 생략하고 싶을 경우 다음 인자에 이름을 붙여 사용 가능)
paramNameTest()// 모두 생략
Java 파일에서 디폴트 파람 기능을 사용 하고자 하면 '@JvmOverloads' 어노테이션을 사용한다
코틀린 컴파일러가 자동으로 맨 마지막 파람부터 하나씩 삭제한 오버로딩 자바 메소드를 사용할 수 있게 해준다
@JvmOverloads
fun paramNameTest( str1: String = "defaultStr1",str2: String = "defaultStr2",str3: String = "defaultSt3") {...}
//만들어진 오버로딩 함수(JAVA에서 호출 가능)
public void paramNameTest(String str1, String str2,String str3){}
public void paramNameTest(String str1, String str2){}
public void paramNameTest(String str1){}
public void paramNameTest(){}
#최상위 함수 (Top-level Function)
- kotlin 파일에서는 클래스 밖에 함수를 선언해서 쓸 수가 있으며 static 메소드 처럼 사용 된다
- Java 파일에선 Uitl 성 함수를 Util 클래스를 생성후 static 함수로 정의해서 사용하곤 했지만 Kotlin에서는 Util 클래스 생성 없이 최상위 함수를 선언해 사용할 수 있다
- 같은 package일 경우 그냥 호출해서 사용할 수 있고 다른 package일 경우 해당 패키지 import 후 사용 할 수 있다
- 컴파일러가 컴파일 시, 최상위 함수를 static 메소드로 포함하는 클래스를 생성해준다(어쨌든 JVM은 클래스 안에 정의된 코드만을 실행 할 수 있기 때문에 / 임의의 클래스 이름은 '파일명+Kt')
- 장점 : 코드 구조를 유연하게 만들 수 있다
//기존 자바에서 으레 사용하는 Util성 함수
public class Utils {
public static void utilMethod() {...}
...
}
정의 / 사용법
//********* FuntionTest.kt *********
package kotlin
fun utilMethod(){} //코틀린에서의 Util 함수 정의
class TestClass(){
fun useUtil(){
utilMethod() //유틸성 함수 사용
}
}
FunctionTest.kt -> Java 로 변경 시
public final class FuntionTestKt { // 컴파일러가 생성 해 준 class
public static final void utilMethod() { //최상위 함수는 static이 함수가 된다
}
}
public final class TestClass {
public final void useUtil() {
FuntionTestKt.utilMethod();
}
}
사용법(Java)
import kotlin.FuntionTestKt;
...
FuntionTestKt.utilMethod();
#최상위 프로퍼티(Top-level Property)
- 프로퍼티도 함수처럼 파일의 최상위 수준에 위치할 수 있으며 static 필드가 된다
- 장점 : 코드 구조를 유연하게 만들 수 있다
정의
//********* PropertyTest.kt *********
package kotlin;
var count =0 //최상위 프로퍼티 var
val countVal =10 //최상위 프로퍼티 val
const val REQUEST_CODE = 100 //최상위 프로퍼티 (상수)
PropertyTest.kt -> Java 로 변경 시
public final class PropertyTestKt {
private static int count;
private static final int countVal = 10;
public static final int REQUEST_CODE = 100;
public static final int getCount() {
return count;
}
public static final void setCount(int var0) {
count = var0;
}
public static final int getCountVal() {
return countVal;
}
}
최상위 프로퍼티도 자바코드에 노출 될 때 접근자 메소드를 통해 사용된다
var 일 땐 getter/setter, val일 땐 getter만 생성이 된다
const 변경자를 붙이면 상수 호출하듯이 getter로 접근이 아닌 필드 바로 접근이 가능하다
(val로 최상위 프로퍼티 선언 시, 의미는 상수 처럼 쓰일 수 있지만 getter로 접근해야 함)
#확장 함수(Extension Function)
- 확장 함수는 어떤 클래스의 멤버 메소드를 추가 생성/호출 해서 사용할 수 있는 것 '처럼' 쓰는 함수(클래스를 확장 개념)
- 실제론 그 클래스 밖에 선언된다
- 확장할 어떤 클래스 이름을 '수신 객체 타입'이라고 하고 확장 함수가 호출될 대상이 되는 인스턴스 객체를 '수신 객체'라고 부른다
- 확장 함수 override는 불가하다(클래스 밖에 선언되며, 수신 객체 변수의 정적 타입에 의해 어떤 확장 함수가 호출될지 결정되기 때문)
- 확장한 클래스의 멤버 함수와 확장 함수의 모양새가 같다면 멤버 함수가 호출된다(멤버 함수의 우선순위가 높음)
- 장점 : 문법적 편의 / 외부 라이브러리에 정의된 클래스 같은 경우에도 클래스의 소스코드를 바꿀 필요 없이 확장 가능
정의
//********* FunctionTest.kt *********
//클래스 선언
class Student(var name: String, var age: Int) {}
//확장 함수 선언 - firstNameChar
//Student = 수신 객체 타입(receiver type) this = 수신 객체(receiver object)
fun Student.firstNameChar(): Char = this.name[0] //학생 이름 첫 Char 반환
사용법
import kotlin.firstNameChar //확장 함수 import
//import kotlin.firstNameChar as firstChar //확장 함수 import 시 as 키워드를 사용해서 다른 이름으로 사용 가능
fun print() {
val student = Student("Tina", 19);
println(student.firstNameChar()) // T
}
확장할 클래스가 직접 작성한 클래스가 아니고 수정할수 없다 하더라도 원하는 메소드를 어떤 클래스에 추가한 것 처럼 사용 할 수 있다
But 확장 함수 안에서, 클래스의 private/protected로 정의된 메소드나 프로퍼티를 사용 할 수는 없다 -> 클래스의 캡슐화는 지켜짐
확장함수는 내부적으로 구현시 아래와 같은 모양을 띄게 된다(확장할 클래스를 첫 번째 인자로 받는 static 메소드)
Java에서는 아래와 같이 사용한다.
확장함수 -> Java 로 변경 시
public final class FuntionTestKt {
public static final char firstNameChar(@NotNull Student $this$firstNameChar) {
Intrinsics.checkNotNullParameter($this$firstNameChar, "$this$firstNameChar");
return $this$firstNameChar.getName().charAt(0);
}
}
사용법(Java)
Student student = new Student("Tina", 19);
Character firstName = FuntionTestKt.firstNameChar(student); //T
확장함수는 오버라이드 되지 않는다! 예제
open class CustomView {
open fun onClick() = println("View is Clicked")
}
class CustomButton : CustomView() {
override fun onClick() = println("Button is Clicked")
}
fun CustomView.expandedOnClick()=println("View Expanded Click")
fun CustomButton.expandedOnClick()=println("Button Expanded Click")
fun main() {
val view: CustomView = CustomView()
val button: CustomView = CustomButton() //컴파일 시점에, 변수의 타입에 따라 어떤 함수가 호출될 지 결정 된다 (CustomView)
view.onClick() //View is Clicked
button.onClick() //Button is Clicked -> Override 성공
view.expandedOnClick() //View Expanded Click
button.expandedOnClick() //View Expanded Click -> Override 실패/안됨
}
#확장 프로퍼티(Extension Property)
- 확장 프로퍼티는 어떤 클래스에 프로퍼티를 추가생성/호출 해서 사용할 수 있는 것 '처럼' 사용
- But 실제 상태를 저장할 뒷받침하는 필드(Backing Field)가 없을 뿐더러 접근자(getter/setter)도 확장 할 클래스의 밖에 선언 되는 방식으므로 실제로 클래스 객체에 필드를 추가한 것은 아니다
- var 선언일 경우 getter/setter 모두 정의
- val 선언일 경우 getter만 정의
- 장점 : 문법적 편의 / 외부 라이브러리에 정의된 클래스 같은 경우에도 클래스의 소스코드를 바꿀 필요 없이 확장 가능
정의
//********* FunctionTest.kt *********
//클래스 선언
//name의 char 변경을 위해 StringBuilder 사용
class Student(var name: StringBuilder, var age: Int) {}
//확장 프로퍼티 선언
var Student.firstNameChar: Char
get() = this.name[0]
set(firstName: Char) {
this.name.setCharAt(0, firstName)
}
사용법
fun print() {
val student = Student(StringBuilder("Tina"), 19)
println(student.firstNameChar()) // T
}
확장 프로퍼티 -> Java 로 변경 시
public final class FuntionTestKt {
public static final char getFirstNameChar(@NotNull Student $this$firstNameChar) {
Intrinsics.checkNotNullParameter($this$firstNameChar, "$this$firstNameChar");
return $this$firstNameChar.getName().charAt(0);
}
public static final void setFirstNameChar(@NotNull Student $this$firstNameChar, char firstName) {
Intrinsics.checkNotNullParameter($this$firstNameChar, "$this$firstNameChar");
$this$firstNameChar.getName().setCharAt(0, firstName);
}
}
사용법(Java)
getter/setter 명시적 사용
Student student = new Student(new StringBuilder("Tina"), 19);
Character firstName = FuntionTestKt.getFirstNameChar(student); //T
FuntionTestKt.setFirstNameChar(student,'t');
Character changedFirstName = FuntionTestKt.getFirstNameChar(student); //t
*코틀린 -> 자바 변경 방법
Android Studio : Tools -> Kotlin -> Show Kotlin ByteCode -> Decompile
*자바와 코틀린이 100% 호환되는 이유
둘다 컴파일 후 .class 파일 즉 ByteCode로 변환되기 때문
출처 : Kotlin In Action - 에이콘 출판사
(위 도서를 학습하고 개인 학습용으로 정리한 내용입니다)
문제 있을시 알려 주세요.
좋은 하루 되세요!
'Kotlin' 카테고리의 다른 글
[Kotlin] 3. Data Class, by (0) | 2021.11.07 |
---|---|
[Kotlin] 3.Interface, Class, 변경자, 초기화블록, 추상 프로퍼티 (0) | 2021.11.06 |
[Kotlin] 2. 코틀린 기본 - 함수(2) (0) | 2021.11.02 |
[Kotlin] 2. 코틀린 기본 - 맛보기 (0) | 2021.10.18 |
[Kotlin] 1. 코틀린이란? (0) | 2021.10.17 |