在没有深入字节码之前,我对kotlin是抱有很多的憧憬,在具体的写代码时候,确实也感觉到了很多方便的语法糖,方便我们快速开发。
但是突然,我想看下 kotlin 生成的字节码和 java 生成的字节码有什么不同,就发现了背后的秘密。
1. 常量中的秘密
1.1 全局静态常量 变量
定义常量变量
1
2
3
4
5
6
7
8
9
10
|
//Valvarconst.kt`
const val name1 = "const"
val name2 = "val"
var name3 = "var"
object CName {
const val name = "CName_val"
}
|
通过 javap -c ValvarconstKt.class
得到字节码,可以发现生成了静态的常量name1,getName2() getName3(),setName3(java.lang.String),他们都是在ValvarconstKt类中定义的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Compiled from "valvarconst.kt"
public final class ValvarconstKt {
public static final java.lang.String name1;
public static final java.lang.String getName2();
Code:
0: getstatic #16 // Field name2:Ljava/lang/String;
3: areturn
public static final java.lang.String getName3();
Code:
0: getstatic #20 // Field name3:Ljava/lang/String;
3: areturn
public static final void setName3(java.lang.String);
Code:
0: aload_0
1: ldc #24 // String <set-?>
3: invokestatic #30 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_0
7: putstatic #20 // Field name3:Ljava/lang/String;
10: return
}
|
假如我在其他类中进行使用,只是单纯的使用以下:
1
2
3
4
|
//TestValVarConst.kt
fun main() {
name1
}
|
会得到如下的代码,因为name1并没有实际的输出,那么生成的字节码就会过滤这条语句,用nop(空指令)来代替。在编译期对代码进行了优化。
1
2
3
4
5
6
7
8
9
10
11
12
|
Compiled from "TestValVarConst.kt"
public final class TestValVarConstKt {
public static final void main();
Code:
0: nop
1: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #9 // Method main:()V
3: return
}
|
修改代码如下,来看一下如果打印输出值的字节码
1
2
3
4
5
6
7
|
//TestValVarConst.kt
fun main() {
println(name1)
println(name2)
println(name3)
println(CName.name)
}
|
分析之后得到如下结果:
- name1 会在编译器直接把值写入到代码中。
- name2 会通过执行getName2()函数得到具体的值。
- name3 会通过执行getName3()函数得到具体的值。
- CName.name 会通过编译器字节把值写入到代码中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
Compiled from "TestValVarConst.kt"
public final class TestValVarConstKt {
public static final void main();
Code:
0: ldc #11 // String const
2: astore_0
3: iconst_0
4: istore_1
5: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream;
8: aload_0
9: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
12: invokestatic #29 // Method ValvarconstKt.getName2:()Ljava/lang/String;
15: astore_0
16: iconst_0
17: istore_1
18: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream;
21: aload_0
22: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
25: invokestatic #32 // Method ValvarconstKt.getName3:()Ljava/lang/String;
28: astore_0
29: iconst_0
30: istore_1
31: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream;
34: aload_0
35: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
38: ldc #34 // String CName_val
40: astore_0
41: iconst_0
42: istore_1
43: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream;
46: aload_0
47: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
50: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #9 // Method main:()V
3: return
}
|
1.2 kotlin 中类中的常量
我想用 kotlin 生成一个和类相关的静态的全局常量,该怎么写呢?
我写的代码,不知道大家和我写的一样不一样,代码如下
1
2
3
4
5
|
class ConstantK {
companion object {
const val name = "12312"
}
}
|
执行 javap -p -v -c ConstantK.class
命令,得到具体的字节码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
Classfile /vip/ruoyun/googleaac/json/ConstantK.class
Last modified 2020-3-2; size 949 bytes
MD5 checksum 195be2ba1519cd25bdd001d4cd7abd07
Compiled from "ConstantK.kt"
public final class vip.ruoyun.googleaac.json.ConstantK
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
Constant pool:
#1 = Utf8 vip/ruoyun/googleaac/json/ConstantK
#2 = Class #1 // vip/ruoyun/googleaac/json/ConstantK
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = NameAndType #5:#6 // "<init>":()V
#8 = Methodref #4.#7 // java/lang/Object."<init>":()V
#9 = Utf8 this
#10 = Utf8 Lvip/ruoyun/googleaac/json/ConstantK;
#11 = Utf8 name
#12 = Utf8 Ljava/lang/String;
#13 = Utf8 12312
#14 = String #13 // 12312
#15 = Utf8 Lorg/jetbrains/annotations/NotNull;
#16 = Utf8 <clinit>
#17 = Utf8 Companion
#18 = Utf8 Lvip/ruoyun/googleaac/json/ConstantK$Companion;
#19 = Utf8 Lkotlin/Metadata;
#20 = Utf8 mv
#21 = Integer 1
#22 = Integer 16
#23 = Utf8 bv
#24 = Integer 0
#25 = Integer 3
#26 = Utf8 k
#27 = Utf8 d1
#28 = Utf8
\n\n\ 20:B¢¨
#29 = Utf8 d2
#30 = Utf8
#31 = Utf8 app_debug
#32 = Utf8 vip/ruoyun/googleaac/json/ConstantK$Companion
#33 = Class #32 // vip/ruoyun/googleaac/json/ConstantK$Companion
#34 = Utf8 (Lkotlin/jvm/internal/DefaultConstructorMarker;)V
#35 = NameAndType #5:#34 // "<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
#36 = Methodref #33.#35 // vip/ruoyun/googleaac/json/ConstantK$Companion."<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
#37 = NameAndType #17:#18 // Companion:Lvip/ruoyun/googleaac/json/ConstantK$Companion;
#38 = Fieldref #2.#37 // vip/ruoyun/googleaac/json/ConstantK.Companion:Lvip/ruoyun/googleaac/json/ConstantK$Companion;
#39 = Utf8 ConstantK.kt
#40 = Utf8 ConstantValue
#41 = Utf8 RuntimeInvisibleAnnotations
#42 = Utf8 Code
#43 = Utf8 LineNumberTable
#44 = Utf8 LocalVariableTable
#45 = Utf8 InnerClasses
#46 = Utf8 SourceFile
#47 = Utf8 RuntimeVisibleAnnotations
{
public static final java.lang.String name;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: String 12312
RuntimeInvisibleAnnotations:
0: #15()
public static final vip.ruoyun.googleaac.json.ConstantK$Companion Companion;
descriptor: Lvip/ruoyun/googleaac/json/ConstantK$Companion;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
public vip.ruoyun.googleaac.json.ConstantK();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 10: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lvip/ruoyun/googleaac/json/ConstantK;
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=3, locals=0, args_size=0
0: new #33 // class vip/ruoyun/googleaac/json/ConstantK$Companion
3: dup
4: aconst_null
5: invokespecial #36 // Method vip/ruoyun/googleaac/json/ConstantK$Companion."<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
8: putstatic #38 // Field Companion:Lvip/ruoyun/googleaac/json/ConstantK$Companion;
11: return
}
InnerClasses:
public static final #17= #33 of #2; //Companion=class vip/ruoyun/googleaac/json/ConstantK$Companion of class vip/ruoyun/googleaac/json/ConstantK
SourceFile: "ConstantK.kt"
|
分析上面的代码,让我们来写一个直观的伪代码来更好的了解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public final class ConstantK {
public static final String name = "12312";
public static final Companion companion = null;
public ConstantK() {
super();
}
public static final class Companion {
private Companion() {
super();
}
}
static {
companion = new Companion();
}
}
|
可以看出,通过 kotlin 的伴生对象生成的静态常量,是在原类中生成一个静态内部类,然后顶一个静态的类的引用,在静态代码块中对这个内部类初始化,这样就可以在 kotlin 中通过ConstantK.name
使用常量了。
1.3 java 中的常量
让我们来看一下 java 中是如何定义常量的。
1
2
3
|
public class Constant {
public final static String name = "121928";
}
|
看一下它的字节码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
Classfile /vip/ruoyun/googleaac/json/Constant.class
Last modified 2020-3-2; size 373 bytes
MD5 checksum 15d9d1e6b1824f3ccbbae2eeea846a3b
Compiled from "Constant.java"
public class vip.ruoyun.googleaac.json.Constant
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#17 // java/lang/Object."<init>":()V
#2 = Class #18 // vip/ruoyun/googleaac/json/Constant
#3 = Class #19 // java/lang/Object
#4 = Utf8 name
#5 = Utf8 Ljava/lang/String;
#6 = Utf8 ConstantValue
#7 = String #20 // 121928
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 LocalVariableTable
#13 = Utf8 this
#14 = Utf8 Lvip/ruoyun/googleaac/json/Constant;
#15 = Utf8 SourceFile
#16 = Utf8 Constant.java
#17 = NameAndType #8:#9 // "<init>":()V
#18 = Utf8 vip/ruoyun/googleaac/json/Constant
#19 = Utf8 java/lang/Object
#20 = Utf8 121928
{
public static final java.lang.String name;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: String 121928
public vip.ruoyun.googleaac.json.Constant();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 9: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lvip/ruoyun/googleaac/json/Constant;
}
SourceFile: "Constant.java"
|
可以看出,里面没有类的生成,如果想使用的话,通过Constant.name
来使用。
1.4 更多思考
有位同学问我如果是加上@JvmStatic变量的话,结果会不会不一样呢?
增加的代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class ConstantK {
companion object {
const val name = "12312"
@JvmStatic
val name1 = "777"
}
fun test() {
print(ConstantK.name)
print(ConstantK.name1)
print(ConstantK.Companion.name)
print(ConstantK.Companion.name1)
}
}
|
查看一下字节码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
Classfile /vip/ruoyun/googleaac/json/ConstantK.class
public static final java.lang.String name;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: String 12312
RuntimeInvisibleAnnotations:
0: #31()
private static final java.lang.String name1;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL
ConstantValue: String 777
RuntimeInvisibleAnnotations:
0: #31()
public static final vip.ruoyun.googleaac.json.ConstantK$Companion Companion;
descriptor: Lvip/ruoyun/googleaac/json/ConstantK$Companion;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
public final void test();
descriptor: ()V
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=3, args_size=1
0: ldc #8 // String 12312
2: astore_1
3: iconst_0
4: istore_2
5: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
8: aload_1
9: invokevirtual #20 // Method java/io/PrintStream.print:(Ljava/lang/Object;)V
12: getstatic #24 // Field name1:Ljava/lang/String;
15: astore_1
16: iconst_0
17: istore_2
18: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
21: aload_1
22: invokevirtual #20 // Method java/io/PrintStream.print:(Ljava/lang/Object;)V
25: ldc #8 // String 12312
27: astore_1
28: iconst_0
29: istore_2
30: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: invokevirtual #20 // Method java/io/PrintStream.print:(Ljava/lang/Object;)V
37: getstatic #24 // Field name1:Ljava/lang/String;
40: astore_1
41: iconst_0
42: istore_2
43: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
46: aload_1
47: invokevirtual #20 // Method java/io/PrintStream.print:(Ljava/lang/Object;)V
50: return
LineNumberTable:
line 19: 0
line 20: 12
line 21: 25
line 22: 37
line 23: 50
LocalVariableTable:
Start Length Slot Name Signature
0 51 0 this Lvip/ruoyun/googleaac/json/ConstantK;
public vip.ruoyun.googleaac.json.ConstantK();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #29 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 10: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lvip/ruoyun/googleaac/json/ConstantK;
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=3, locals=0, args_size=0
0: new #56 // class vip/ruoyun/googleaac/json/ConstantK$Companion
3: dup
4: aconst_null
5: invokespecial #59 // Method vip/ruoyun/googleaac/json/ConstantK$Companion."<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
8: putstatic #54 // Field Companion:Lvip/ruoyun/googleaac/json/ConstantK$Companion;
11: ldc #33 // String 777
13: putstatic #24 // Field name1:Ljava/lang/String;
16: return
LineNumberTable:
line 14: 11
public static final java.lang.String access$getName1$cp();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
Code:
stack=1, locals=0, args_size=0
0: getstatic #24 // Field name1:Ljava/lang/String;
3: areturn
LineNumberTable:
line 10: 0
public static final java.lang.String getName1();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Code:
stack=2, locals=0, args_size=0
0: getstatic #54 // Field Companion:Lvip/ruoyun/googleaac/json/ConstantK$Companion;
3: getstatic #24 // Field name1:Ljava/lang/String;
6: areturn
RuntimeInvisibleAnnotations:
0: #31()
}
InnerClasses:
public static final #35= #56 of #2; //Companion=class vip/ruoyun/googleaac/json/ConstantK$Companion of class vip/ruoyun/googleaac/json/ConstantK
SourceFile: "ConstantK.kt"
|
伪代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public final class ConstantK {
public static final String name = "12312";
public static final String name1 = "777";
public static final Companion companion = null;
public ConstantK() {
super();
}
public static final class Companion {
private Companion() {
super();
}
public static final String getName1(){
return name1;
}
}
static {
companion = new Companion();
name1 = "777";
}
public static synthetic final String access$getName1$cp(){
return name1;
}
}
|
可以看到生成了更多的方法,并在初始化的时候,对name1
又进行一遍赋值。
1.5 小结
通过比较,我们可以看到在 kotlin 中生成一个和类无关的常量和变量的时候,是和 java 中是一样的,但是如果想要在 kotlin 中在类中生成一个静态常量和变量的时候,就会通过伴生对象来操作。
所以如果想要生成一个和类绑定的常量或者变量的时候,java更简单一些。
2. 单例对象
2.1 饿汉式单例
在 kotlin 中,可以通过 object 来声明一个饿汉式单例,字节在加载类的时候就创建了对象。
1
2
3
4
|
//TestObject.kt
object TestObject {
const val name = "123"
}
|
javap -c TestObject.class
,可以发现会有一个静态的不可变的变量INSTANCE,然后再static 中对INSTANCE就行赋值。这样就可以生成一个静态对象,这样在类加载的时候就创建了这个对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Compiled from "TestObject.kt"
public final class TestObject {
public static final java.lang.String name;
public static final TestObject INSTANCE;
static {};
Code:
0: new #2 // class TestObject
3: dup
4: invokespecial #31 // Method "<init>":()V
7: astore_0
8: aload_0
9: putstatic #33 // Field INSTANCE:LTestObject;
12: return
}
|
和java中的使用 static 变量一样。线程安全,但是加载类慢。
1
2
3
4
5
6
7
8
9
10
|
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
|
2.2 kotlin中的懒汉式单例
1
2
3
4
5
6
7
8
9
10
11
12
|
//单例
class Single private constructor() {
companion object {
fun get(): Single {
return Holder.instance
}
private object Holder {
val instance = Single()
}
}
}
|
伴生对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
Compiled from "Single.kt"
public final class Single {
public static final Single$Companion Companion;
static {};
Code:
0: new #32 // class Single$Companion
3: dup
4: aconst_null
5: invokespecial #34 // Method Single$Companion."<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
8: putstatic #36 // Field Companion:LSingle$Companion;
11: return
public Single(kotlin.jvm.internal.DefaultConstructorMarker);
Code:
0: aload_0
1: invokespecial #15 // Method "<init>":()V
4: return
}
|
javap -c Single$Companion.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Compiled from "Single.kt"
public final class Single$Companion {
public final Single get();
Code:
0: getstatic #13 // Field Single$Companion$Holder.INSTANCE:LSingle$Companion$Holder;
3: invokevirtual #16 // Method Single$Companion$Holder.getInstance:()LSingle;
6: areturn
public Single$Companion(kotlin.jvm.internal.DefaultConstructorMarker);
Code:
0: aload_0
1: invokespecial #24 // Method "<init>":()V
4: return
}
|
javap -c Single$Companion$Holder.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
Compiled from "Single.kt"
final class Single$Companion$Holder {
public static final Single$Companion$Holder INSTANCE;
public final Single getInstance();
Code:
0: getstatic #11 // Field instance:LSingle;
3: areturn
static {};
Code:
0: new #2 // class Single$Companion$Holder
3: dup
4: invokespecial #33 // Method "<init>":()V
7: astore_0
8: aload_0
9: putstatic #35 // Field INSTANCE:LSingle$Companion$Holder;
12: new #37 // class Single
15: dup
16: aconst_null
17: invokespecial #40 // Method Single."<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
20: putstatic #11 // Field instance:LSingle;
23: return
}
|
在get() 方法的时候,就会加载Holder类(静态内部类),然后执行Holder类的static 函数,创建Holder对象,创建Single对象,然后执行Holder.getInstance()函数,得到具体的单例对象。
2.3 java中的懒汉式单例
其实这和java 中的静态内部类的方式是异曲同工。
1
2
3
4
5
6
7
8
9
10
11
12
|
public class TestJavaSingle {
private static class Holder {
private static final TestJavaSingle SINGLE = new TestJavaSingle();
}
private TestJavaSingle() {}
public static TestJavaSingle getInstance() {
return Holder.SINGLE;
}
}
|
javap -c TestJavaSingle$Holder.class
1
2
3
4
5
6
7
8
9
10
|
Compiled from "TestJavaSingle.java"
class TestJavaSingle$Holder {
static {};
Code:
0: new #7 // class TestJavaSingle
3: dup
4: invokespecial #9 // Method TestJavaSingle."<init>":()V
7: putstatic #10 // Field SINGLE:LTestJavaSingle;
10: return
}
|
javap -c TestJavaSingle.class
1
2
3
4
5
6
7
|
Compiled from "TestJavaSingle.java"
public class TestJavaSingle {
public static TestJavaSingle getInstance();
Code:
0: getstatic #7 // Field TestJavaSingle$Holder.SINGLE:LTestJavaSingle;
3: areturn
}
|
可以看到通过getInstance()方法,加载静态内部类,在加载静态内部类的同时会调用静态内部类的static 代码快,在代码块中创建了单例对象。由于jvm 在加载一个类的时候,是保证只会加载一份class,所以是多线程安全的。
2.4 小结
在kotlin 中生成一个懒汉式单例,需要在伴生对象中定义一个 Object 的对象,这样的话,其实是包装了 3 层类,最后才得到具体的单例对象。
而 java 中,只需要 2 个类就可以实现懒汉式的单例。
3. 总结
感觉从现在的角度看,kotlin生成的字节码降低了代码的执行效率,并且增大了代码体积。
其实 jvm 在针对用 final static 修饰的基本类型,如果只是调用这些属性的话,在 jvm 中,class 对象只会进行加载和连接,但是并不会初始化,也就是不会执行 static 代码块。
4. 我想说的话
其实对于kotlin 成为 android 的第一语言,我们没必要追求项目都是使用 kotlin 来开发,甚至所有的库都想要换成 kotlin ,抛弃一切和 java 相关的代码,我觉得这些都没有必要,java 在代码的简洁程度上是高于 kotlin 的,生成的字节码也是如此,所以在运行的效率上 java 在很多地方都是要高于 kotlin 。
我们在写项目的时候,没必要纠结 all in kotlin,应该选用效率最高,编写更好的语言,所以在 Android 开发中,混合编程方显共赢!
如果你喜欢我的文章,可以关注我的掘金、公众号、博客、简书或者Github!
简书: https://www.jianshu.com/u/a2591ab8eed2
GitHub: https://github.com/bugyun
Blog: https://ruoyun.vip
掘金: https://juejin.im/user/56cbef3b816dfa0059e330a8/posts
CSDN: https://blog.csdn.net/zxloveooo
欢迎关注微信公众号
