inline
이를 Inline으로 선언해 주면 객체를 생성하지 않아 오버헤드가 발생하지 않지만 객체를 생성하는 대신 코드를 copy하기 때문에 코드의 양이 많은 함수는 inline을 사용하지 않는게 좋다. 보통 1~3줄의 경우에 사용하는게 좋다.
inline함수의 인자로 고차 함수가 존재할 수 있는데 별도 처리를 해주지 않으면 코드를 생성하여 객체를 생성하지 않는다.
하지만 inline함수내에서 다른 함수를 호출할 경우나 전달 받은 파라미터 함수의 사이즈가 너무 커서 inline을 사용하는게 좋지 않은 경우가 있을 수 있다.
이경우에 파라미터에 @noninline 어노테이션을 달아 주면 코드를 생성하지 않고 객체를 생성한다.
Reified
제네릭에서는 Type erasure (타입 파라미터 소거라 불리며 흔히 제네릭에서 사용된다. 제네릭의 경우 특정 타입이 맞는지 확인하는 is의 과정을 거치지 않는데 이를 타입 소거라고 한다. ) 때문에 파라미터 타입에 직접 접근이 불가능 하다.
fun <T> print(value: T) {
when (value::class) { // 런타임에서 타입이 지워지기 때문에 컴파일 에러가 발생한다.
String::class.java -> {
println("String : $value")
}
else -> {
println("${value!!::class.java.name} : $value")
}
}
}
이때 파라미터에 직접 접근하는 방법이 두가지가 있는데
하나는 아래와 같이 해당 파라미터에 classType을 직접 받는 경우이다.
fun <T> print(value: T, classType: Class<T>) {
when (classType) {
String::class.java -> {
println("String : $value")
}
else -> {
println("${value!!::class.java.name} : $value")
}
}
}
fun test() {
val value = 1.0
print(value, value.javaClass)
}
출력
java.lang.Double : 1.0
아래와 같이 Double 타입을 직접 전달해 준다.
public final void test() {
double value = 1.0D;
this.print(value, Double.TYPE);
}
public final void print(Object value, @NotNull Class classType) {
Intrinsics.checkNotNullParameter(classType, "classType");
String var4;
if (Intrinsics.areEqual(classType, String.class)) {
var4 = "String : " + value;
System.out.println(var4);
} else {
StringBuilder var10000 = new StringBuilder();
Intrinsics.checkNotNull(value);
var4 = var10000.append(value.getClass().getName()).append(" : ").append(value).toString();
System.out.println(var4);
}
}
다른 방법은 inline의 Reified를 통하여 파라미터에 직접 접근하는 방법이다.
inline fun <reified T> print(value: T) {
when (T::class) {
String::class -> {
println("String : $value")
}
else -> {
println("${value!!::class.java.name} : $value")
}
}
}
fun test() {
val value = 1.0
print(value)
}
출력
java.lang.Double : 1.0
하지만 inline 함수 이기 때문에 실제 타입이 사용된 코드를 생성함으로 코드량이 많은 함수의 경우 오버헤드가 발생한다.
아래 코드와 같이 test()함수에서 Reified함수인 print()를 호출할 때 String인지 아닌지(print()함수와 같은 로직) 코드를 직접 생성한다.
@Test
public final void test() {
double value = 1.0D;
Object value$iv = value;
int $i$f$print = false;
KClass var6 = Reflection.getOrCreateKotlinClass(Double.class);
String var7;
if (Intrinsics.areEqual(var6, Reflection.getOrCreateKotlinClass(String.class))) {
var7 = "String : " + value$iv;
System.out.println(var7);
} else {
var7 = value$iv.getClass().getName() + " : " + value$iv;
System.out.println(var7);
}
}
// $FF: synthetic method
public final void print(Object value) {
int $i$f$print = 0;
Intrinsics.reifiedOperationMarker(4, "T");
KClass var3 = Reflection.getOrCreateKotlinClass(Object.class);
String var4;
if (Intrinsics.areEqual(var3, Reflection.getOrCreateKotlinClass(String.class))) {
var4 = "String : " + value;
System.out.println(var4);
} else {
StringBuilder var10000 = new StringBuilder();
Intrinsics.checkNotNull(value);
var4 = var10000.append(value.getClass().getName()).append(" : ").append(value).toString();
System.out.println(var4);
}
}
참고
https://www.youtube.com/watch?v=Xj45hobMI78
https://medium.com/android-news/learning-kotlin-inline-functions-18a94d3efe46
'코틀린' 카테고리의 다른 글
코틀린 제네릭이란? (in, out) (1) | 2025.01.14 |
---|---|
불변 객체 (0) | 2022.12.14 |
코틀린 by란? (0) | 2022.06.28 |
코틀린 플로우 (0) | 2022.06.01 |
비동기 callback을 동기로 처리하기 suspendCoroutine, suspendCancellableCoroutine (0) | 2022.05.23 |