Kotlin 中的类属性是如何实现的
在 kotlin
中,我们可以定义类属性,那么这些类属性在 class
文件中是如何实现的呢?
结论
在对应的 class
文件中,会为
- 作为
val
的类属性生成对应的field
/getter
- 作为
var
的类属性生成对应的field
/getter
/setter
代码
我们用如下代码来进行分析(请将代码保存为 A.kt
)。
kotlin
class Human {
val name = "张无忌";
var age = 18;
}
fun main(args: Array<String>) {
val human = Human()
println("${human.name} 的年龄是 ${human.age}")
}
下方的命令可以编译 A.kt
。
bash
kotlinc A.kt
编译 A.kt
后,我们会看到如下的 class
文件
text
AKt.class
Human.class
查看 Human
类
我们可以用如下的命令查看 Human.class
的内容
bash
javap -v -p Human
部分结果展示如下(常量池等部分已经略去)
text
{
private final java.lang.String name;
descriptor: Ljava/lang/String;
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
RuntimeInvisibleAnnotations:
0: #23()
org.jetbrains.annotations.NotNull
private int age;
descriptor: I
flags: (0x0002) ACC_PRIVATE
public Human();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #10 // String 张无忌
7: putfield #14 // Field name:Ljava/lang/String;
10: aload_0
11: bipush 18
13: putfield #18 // Field age:I
16: return
LineNumberTable:
line 1: 0
line 2: 4
line 3: 10
line 1: 16
LocalVariableTable:
Start Length Slot Name Signature
0 17 0 this LHuman;
public final java.lang.String getName();
descriptor: ()Ljava/lang/String;
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #14 // Field name:Ljava/lang/String;
4: areturn
LineNumberTable:
line 2: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LHuman;
RuntimeInvisibleAnnotations:
0: #23()
org.jetbrains.annotations.NotNull
public final int getAge();
descriptor: ()I
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #18 // Field age:I
4: ireturn
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LHuman;
public final void setAge(int);
descriptor: (I)V
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: iload_1
2: putfield #18 // Field age:I
5: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this LHuman;
0 6 1 <set-?> I
}
基于 javap
命令给出的结果,我们可以反推出对应的 java
源码是这样的(假如源码是 java
的话)⬇️
java
// 以下代码是我手动转化的,不保证绝对准确,仅供参考
// 类上有注解,这里略,有兴趣的读者朋友可以自行查看它的具体内容
public final class Human {
@org.jetbrains.annotations.NotNull
private final java.lang.String name;
private int age;
public Human() {
super();
this.name = "张无忌";
this.age = 18;
}
@org.jetbrains.annotations.NotNull
public final java.lang.String getName() {
return this.name;
}
public final int getAge() {
return this.age;
}
// 其实 "<set-?>" 这个变量名在 java 中并不合法。我是从 LocalVariableTable 属性看到这个变量名的,在这里我只是如实把它粘贴过来了
public final void setAge(int <set-?>) {
this.age = <set-?>;
}
}
在 kotlin
源码的 Human
类中,name
是 val
,age
是 var
。 在 Human.class
文件中,可以找到
- 和作为
val
的name
对应的field
/getter
- 和作为
var
的age
对应的field
/getter
/setter