Kotlin字節(jié)碼層探究構(gòu)造函數(shù)與成員變量和init代碼塊執(zhí)行順序
之前寫了一篇文章,從Java語法的角度分析了Kotlin構(gòu)造函數(shù)、成員變量初始化、init代碼塊三者的執(zhí)行順序:
Kotlin構(gòu)造函數(shù)與成員變量和init代碼塊執(zhí)行順序詳細講解
這次再從字節(jié)碼的角度分析它們的執(zhí)行順序。
還是用之前那個例子:
class InitOrderDemo(name: String) {
val firstProperty = "First property: $name".also(::println)
init {
println("First initializer block that prints ${name}")
}
val secondProperty = "Second property: ${name.length}".also(::println)
init {
println("Second initializer block that prints ${name.length}")
}
}調(diào)用InitOrderDemo(“hello”)打印的結(jié)果如下:
First property: hello
First initializer block that prints hello
Second property: 5
Second initializer block that prints 5
可以看到執(zhí)行順序,是按照它們聲明的順序執(zhí)行。
將上面Koltin代碼轉(zhuǎn)成字節(jié)碼之后,顯示內(nèi)容如下:
// ================com/devnn/javalib/InitOrderDemo.class =================
// class version 52.0 (52)
// access flags 0x31
public final class com/devnn/javalib/InitOrderDemo {
// access flags 0x12
private final Ljava/lang/String; firstProperty
@Lorg/jetbrains/annotations/NotNull;() // invisible
// access flags 0x11
public final getFirstProperty()Ljava/lang/String;
@Lorg/jetbrains/annotations/NotNull;() // invisible
L0
LINENUMBER 4 L0
ALOAD 0
GETFIELD com/devnn/javalib/InitOrderDemo.firstProperty : Ljava/lang/String;
ARETURN
L1
LOCALVARIABLE this Lcom/devnn/javalib/InitOrderDemo; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x12
private final Ljava/lang/String; secondProperty
@Lorg/jetbrains/annotations/NotNull;() // invisible
// access flags 0x11
public final getSecondProperty()Ljava/lang/String;
@Lorg/jetbrains/annotations/NotNull;() // invisible
L0
LINENUMBER 10 L0
ALOAD 0
GETFIELD com/devnn/javalib/InitOrderDemo.secondProperty : Ljava/lang/String;
ARETURN
L1
LOCALVARIABLE this Lcom/devnn/javalib/InitOrderDemo; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public <init>(Ljava/lang/String;)V
// annotable parameter count: 1 (visible)
// annotable parameter count: 1 (invisible)
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 1
LDC "name"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkNotNullParameter (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 3 L1
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L2
LINENUMBER 4 L2
ALOAD 0
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "First property: "
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 2
L3
ALOAD 2
ASTORE 3
L4
LINENUMBER 17 L4
ASTORE 5
L5
ICONST_0
ISTORE 4
L6
LINENUMBER 4 L6
L7
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 3
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L8
L9
L10
GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
ASTORE 6
ALOAD 5
L11
LINENUMBER 4 L11
L12
ALOAD 2
L13
PUTFIELD com/devnn/javalib/InitOrderDemo.firstProperty : Ljava/lang/String;
L14
LINENUMBER 6 L14
NOP
L15
LINENUMBER 7 L15
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "First initializer block that prints "
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 2
L16
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L17
L18
LINENUMBER 8 L18
NOP
L19
LINENUMBER 10 L19
ALOAD 0
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "Second property: "
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/String.length ()I
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 2
L20
ALOAD 2
ASTORE 3
L21
LINENUMBER 17 L21
ASTORE 5
L22
ICONST_0
ISTORE 4
L23
LINENUMBER 10 L23
L24
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 3
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L25
L26
L27
GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
ASTORE 6
ALOAD 5
L28
LINENUMBER 10 L28
L29
ALOAD 2
L30
PUTFIELD com/devnn/javalib/InitOrderDemo.secondProperty : Ljava/lang/String;
L31
LINENUMBER 12 L31
NOP
L32
LINENUMBER 13 L32
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "Second initializer block that prints "
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/String.length ()I
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 2
L33
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L34
L35
LINENUMBER 14 L35
RETURN
L36
LOCALVARIABLE p1 Ljava/lang/Object; L5 L10 3
LOCALVARIABLE $i$a$-unknown-InitOrderDemo$firstProperty$1 I L6 L10 4
LOCALVARIABLE p1 Ljava/lang/Object; L22 L27 3
LOCALVARIABLE $i$a$-unknown-InitOrderDemo$secondProperty$1 I L23 L27 4
LOCALVARIABLE this Lcom/devnn/javalib/InitOrderDemo; L0 L36 0
LOCALVARIABLE name Ljava/lang/String; L0 L36 1
MAXSTACK = 3
MAXLOCALS = 7
}可以看到上面的構(gòu)造函數(shù)、成員變量初始化和init代碼塊,按照聲明都被放到了字節(jié)碼的init代碼塊中了。
字節(jié)碼的init初始化器其實就是類的構(gòu)造函數(shù)。將Java代碼轉(zhuǎn)成字節(jié)碼也是存在init構(gòu)造函數(shù)。
下面看一個Java示例,加深對字節(jié)碼的init初始化塊的認識。
package com.devnn.javalib;
public class JavaInit {
String firstName = "Steven";
{
System.out.println("This is init block");
}
JavaInit(String secondName) {
System.out.println("firstName=" + firstName);
System.out.println("secondName=" + secondName);
}
public static void main(String[] args) {
new JavaInit("Jobs");
}
}運行main函數(shù)打印結(jié)果如下:
This is init block
firstName=Steven
secondName=Jobs
將上面的JavaInit類轉(zhuǎn)成字節(jié)碼之后的內(nèi)容如下:
// class version 51.0 (51)
// access flags 0x21
public class com/devnn/javalib/JavaInit {
// compiled from: JavaInit.java
// access flags 0x0
Ljava/lang/String; firstName
// access flags 0x0
<init>(Ljava/lang/String;)V
L0
LINENUMBER 10 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L1
LINENUMBER 4 L1
ALOAD 0
LDC "Steven"
PUTFIELD com/devnn/javalib/JavaInit.firstName : Ljava/lang/String;
L2
LINENUMBER 7 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "This is init block"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L3
LINENUMBER 11 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "firstName="
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 0
GETFIELD com/devnn/javalib/JavaInit.firstName : Ljava/lang/String;
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L4
LINENUMBER 12 L4
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "secondName="
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L5
LINENUMBER 13 L5
RETURN
L6
LOCALVARIABLE this Lcom/devnn/javalib/JavaInit; L0 L6 0
LOCALVARIABLE secondName Ljava/lang/String; L0 L6 1
MAXSTACK = 3
MAXLOCALS = 2
// access flags 0x9
public static main([Ljava/lang/String;)V
L0
LINENUMBER 16 L0
NEW com/devnn/javalib/JavaInit
DUP
LDC "Jobs"
INVOKESPECIAL com/devnn/javalib/JavaInit.<init> (Ljava/lang/String;)V
POP
L1
LINENUMBER 17 L1
RETURN
L2
LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
MAXSTACK = 3
MAXLOCALS = 1
}可見,Java類的成員變量初始化、構(gòu)造函數(shù)、構(gòu)造塊同樣都被拷貝進了init代碼塊中。那么它們是否存在順序問題呢?
將上面JavaInit類的firname成員變量放到初始化塊下面試試:
package com.devnn.javalib;
public class JavaInit {
{
System.out.println("This is init block");
}
JavaInit(String secondName) {
System.out.println("firstName=" + firstName);
System.out.println("secondName=" + secondName);
}
String firstName = "Steven";
public static void main(String[] args) {
new JavaInit("Jobs");
}
}查看字節(jié)碼:
// class version 51.0 (51)
// access flags 0x21
public class com/devnn/javalib/JavaInit {
// compiled from: JavaInit.java
// access flags 0x0
Ljava/lang/String; firstName
// access flags 0x0
<init>(Ljava/lang/String;)V
L0
LINENUMBER 8 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L1
LINENUMBER 5 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "This is init block"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L2
LINENUMBER 13 L2
ALOAD 0
LDC "Steven"
PUTFIELD com/devnn/javalib/JavaInit.firstName : Ljava/lang/String;
L3
LINENUMBER 9 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "firstName="
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 0
GETFIELD com/devnn/javalib/JavaInit.firstName : Ljava/lang/String;
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L4
LINENUMBER 10 L4
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "secondName="
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L5
LINENUMBER 11 L5
RETURN
L6
LOCALVARIABLE this Lcom/devnn/javalib/JavaInit; L0 L6 0
LOCALVARIABLE secondName Ljava/lang/String; L0 L6 1
MAXSTACK = 3
MAXLOCALS = 2
// access flags 0x9
public static main([Ljava/lang/String;)V
L0
LINENUMBER 17 L0
NEW com/devnn/javalib/JavaInit
DUP
LDC "Jobs"
INVOKESPECIAL com/devnn/javalib/JavaInit.<init> (Ljava/lang/String;)V
POP
L1
LINENUMBER 18 L1
RETURN
L2
LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
MAXSTACK = 3
MAXLOCALS = 1
}可見,Java類的成員變量初始化、構(gòu)造函數(shù)、構(gòu)造塊同樣都被拷貝進了字節(jié)碼init代碼塊中。Java的成員變量初始化和構(gòu)造塊也是按聲明順序執(zhí)行。不同的是,Java的構(gòu)造函數(shù)代碼始終放在了字節(jié)碼init代碼塊的后面。
字節(jié)碼的init初始化塊,其實就是類的真正的構(gòu)造函數(shù)。Kotlin多個init代碼塊都是按照順序拷貝進了字節(jié)碼的init初始化塊中,可以理解為它們是構(gòu)造函數(shù)的組成部分。
Java和kotlin成員變量的初始化都是放到字節(jié)碼的init代碼塊中,也就是在構(gòu)造函數(shù)中執(zhí)行的。
到此這篇關(guān)于Kotlin字節(jié)碼層探究構(gòu)造函數(shù)與成員變量和init代碼塊執(zhí)行順序的文章就介紹到這了,更多相關(guān)Kotlin構(gòu)造函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android ActionBarActivity設置全屏無標題實現(xiàn)方法總結(jié)
這篇文章主要介紹了Android ActionBarActivity設置全屏無標題實現(xiàn)方法總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-04-04
Android項目實戰(zhàn)之Glide 高斯模糊效果的實例代碼
這篇文章主要介紹了Android項目實戰(zhàn)之Glide 高斯模糊效果的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-06-06
ViewPager實現(xiàn)帶引導小圓點與自動跳轉(zhuǎn)的引導界面
這篇文章主要為大家詳細介紹了ViewPager實現(xiàn)帶引導小圓點與自動跳轉(zhuǎn)的引導界面,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11
Android加載loading對話框的功能及實例代碼(不退出沉浸式效果)
這篇文章主要介紹了Android加載loading對話框的功能及實例代碼,不退出沉浸式效果,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2018-12-12

