Kotlin 内联扩展 属性
Kotlin inlined extension property
我知道 inline 关键字意味着避免调用函数的调用开销。但是我不知道内联扩展 属性 有什么用?
假设我们有两个名为 foo 的扩展 属性 和另一个名为 bar
的内联扩展
val Any.foo : Long
get() = Date().time
inline val Any.bar : Long
get() = Date().time
执行其中任何一个,我们都会得到预期的输出,即当前时间。
此文件的字节码如下:
public final class InlinedExtensionPropertyKt {
public final static getFoo(Ljava/lang/Object;)J
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 0
LDC "$receiver"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 9 L1
NEW java/util/Date
DUP
INVOKESPECIAL java/util/Date.<init> ()V
INVOKEVIRTUAL java/util/Date.getTime ()J
LRETURN
L2
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
public final static getBar(Ljava/lang/Object;)J
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 0
LDC "$receiver"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 12 L1
NEW java/util/Date
DUP
INVOKESPECIAL java/util/Date.<init> ()V
INVOKEVIRTUAL java/util/Date.getTime ()J
LRETURN
L2
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
LOCALVARIABLE $i$f$getBar I L0 L2 1
MAXSTACK = 2
MAXLOCALS = 2
@Lkotlin/Metadata;(mv={1, 1, 7}, bv={1, 0, 2}, k=2, d1={"\u0000\u000e\n\u0000\n\u0002\u0010\u0009\n\u0002\u0010\u0000\n\u0002\u0008\u0005\"\u0016\u0010\u0000\u001a\u00020\u0001*\u00020\u00028\u00c6\u0002\u00a2\u0006\u0006\u001a\u0004\u0008\u0003\u0010\u0004\"\u0015\u0010\u0005\u001a\u00020\u0001*\u00020\u00028F\u00a2\u0006\u0006\u001a\u0004\u0008\u0006\u0010\u0004\u00a8\u0006\u0007"}, d2={"bar", "", "", "getBar", "(Ljava/lang/Object;)J", "foo", "getFoo", "test sources for module app"})
// compiled from: InlinedExtensionPropertyKt.kt
}
我们可以看到两者相似但仅在以下几行不同:
foo 提取:
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
bar 摘录:
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
LOCALVARIABLE $i$f$getBar I L0 L2 1
MAXSTACK = 2
MAXLOCALS = 2
我真的不明白这里发生了什么。
有人可以指出我的行为是什么,或者 java 中的等效行为,或者对此有何用途?
编辑
考虑到编译器会替换内联属性的内容,内联每个扩展属性没有繁重的操作会很方便吗?
谢谢
来自 Kotlin's doc,
Note that, since extensions do not actually insert members into classes, there's no efficient way for an extension property to have a backing field.
和also,
The inline
modifier can be used on accessors of properties that don't have a backing field.
如上所述,内联扩展 属性 没有支持字段。您可以将扩展 属性 视为一对静态 getter/setter,如下所示:
//In Kotlin
var Any.foo : Long
get() = Date().time
set(value) {
//Cannot access field here since extension property cannot have backing field
//Do something with `obj`
}
//In Java
public static long getFoo(Object obj) {
return new Date().getTime();
}
public static void setFoo(Object obj) {
//Do something with `obj`
}
因此,inline 属性 意味着 getter/setter 函数的代码将在访问 属性 时被内联到调用站点(与常规内联函数相同)。
//In Kotlin
val x = "".foo
val y = "".bar
//Generated code
val x = InlinedExtensionPropertyKt.getFoo("")
val y = Date().time
对于您在问题中 post 的字节码,抱歉,我无法解释发生了什么。但是你可以试着看看下面代码的字节码:
fun get() {
val x = "".foo
val y = "".bar
}
,其中 "".foo
将调用 getter 函数,但 "".bar
不会。
我知道 inline 关键字意味着避免调用函数的调用开销。但是我不知道内联扩展 属性 有什么用?
假设我们有两个名为 foo 的扩展 属性 和另一个名为 bar
的内联扩展val Any.foo : Long
get() = Date().time
inline val Any.bar : Long
get() = Date().time
执行其中任何一个,我们都会得到预期的输出,即当前时间。
此文件的字节码如下:
public final class InlinedExtensionPropertyKt {
public final static getFoo(Ljava/lang/Object;)J
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 0
LDC "$receiver"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 9 L1
NEW java/util/Date
DUP
INVOKESPECIAL java/util/Date.<init> ()V
INVOKEVIRTUAL java/util/Date.getTime ()J
LRETURN
L2
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
public final static getBar(Ljava/lang/Object;)J
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 0
LDC "$receiver"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 12 L1
NEW java/util/Date
DUP
INVOKESPECIAL java/util/Date.<init> ()V
INVOKEVIRTUAL java/util/Date.getTime ()J
LRETURN
L2
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
LOCALVARIABLE $i$f$getBar I L0 L2 1
MAXSTACK = 2
MAXLOCALS = 2
@Lkotlin/Metadata;(mv={1, 1, 7}, bv={1, 0, 2}, k=2, d1={"\u0000\u000e\n\u0000\n\u0002\u0010\u0009\n\u0002\u0010\u0000\n\u0002\u0008\u0005\"\u0016\u0010\u0000\u001a\u00020\u0001*\u00020\u00028\u00c6\u0002\u00a2\u0006\u0006\u001a\u0004\u0008\u0003\u0010\u0004\"\u0015\u0010\u0005\u001a\u00020\u0001*\u00020\u00028F\u00a2\u0006\u0006\u001a\u0004\u0008\u0006\u0010\u0004\u00a8\u0006\u0007"}, d2={"bar", "", "", "getBar", "(Ljava/lang/Object;)J", "foo", "getFoo", "test sources for module app"})
// compiled from: InlinedExtensionPropertyKt.kt
}
我们可以看到两者相似但仅在以下几行不同:
foo 提取:
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
bar 摘录:
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
LOCALVARIABLE $i$f$getBar I L0 L2 1
MAXSTACK = 2
MAXLOCALS = 2
我真的不明白这里发生了什么。 有人可以指出我的行为是什么,或者 java 中的等效行为,或者对此有何用途?
编辑
考虑到编译器会替换内联属性的内容,内联每个扩展属性没有繁重的操作会很方便吗?
谢谢
来自 Kotlin's doc,
Note that, since extensions do not actually insert members into classes, there's no efficient way for an extension property to have a backing field.
和also,
The
inline
modifier can be used on accessors of properties that don't have a backing field.
如上所述,内联扩展 属性 没有支持字段。您可以将扩展 属性 视为一对静态 getter/setter,如下所示:
//In Kotlin
var Any.foo : Long
get() = Date().time
set(value) {
//Cannot access field here since extension property cannot have backing field
//Do something with `obj`
}
//In Java
public static long getFoo(Object obj) {
return new Date().getTime();
}
public static void setFoo(Object obj) {
//Do something with `obj`
}
因此,inline 属性 意味着 getter/setter 函数的代码将在访问 属性 时被内联到调用站点(与常规内联函数相同)。
//In Kotlin
val x = "".foo
val y = "".bar
//Generated code
val x = InlinedExtensionPropertyKt.getFoo("")
val y = Date().time
对于您在问题中 post 的字节码,抱歉,我无法解释发生了什么。但是你可以试着看看下面代码的字节码:
fun get() {
val x = "".foo
val y = "".bar
}
,其中 "".foo
将调用 getter 函数,但 "".bar
不会。