[Kotlin] 类属性是如何实现的

Kotlin 中的类属性是如何实现的

kotlin 中,我们可以定义类属性,那么这些类属性在 class 文件中是如何实现的呢?

结论

在对应的 class 文件中,会为

  1. 作为 val 的类属性生成对应的 field/getter
  2. 作为 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 类中,namevalagevar。 在 Human.class 文件中,可以找到

  1. 和作为 valname 对应的 field/getter
  2. 和作为 varage 对应的 field/getter/setter
相关推荐
小码哥_常2 小时前
Kotlin RecyclerView数据错乱大作战:从"鬼打墙"到丝滑大师
android·kotlin
Kiri霧8 小时前
Kotlin main函数
android·开发语言·kotlin
xzkyd outpaper9 小时前
Android CameraX使用
android·架构·kotlin·计算机八股
儿歌八万首17 小时前
Jetpack Compose 中 Kotlin 协程的使用
android·ui·kotlin·协程·compose
Kiri霧1 天前
Kotlin集合分组
android·java·前端·kotlin
小码哥_常2 天前
【Kotlin进阶秘籍】7个让代码优雅到飞起的骚操作!
前端·kotlin
消失的旧时光-19433 天前
Android模块化架构:基于依赖注入和服务定位器的解耦方案
android·java·架构·kotlin
Kiri霧3 天前
Kotlin重写函数中的命名参数
android·开发语言·javascript·kotlin
RichardLai884 天前
实战搭建:MVVM + Hilt + Retrofit + Compose + MockK 的完整 Android 项目
android·前端·kotlin