Kotlin字節(jié)碼層探究構(gòu)造函數(shù)與成員變量和init代碼塊執(zhí)行順序
之前寫了一篇文章,從Java語法的角度分析了Kotlin構(gòu)造函數(shù)、成員變量初始化、init代碼塊三者的執(zhí)行順序:
Kotlin構(gòu)造函數(shù)與成員變量和init代碼塊執(zhí)行順序詳細(xì)講解
這次再從字節(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初始化器其實(shí)就是類的構(gòu)造函數(shù)。將Java代碼轉(zhuǎn)成字節(jié)碼也是存在init構(gòu)造函數(shù)。
下面看一個Java示例,加深對字節(jié)碼的init初始化塊的認(rèn)識。
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"); } }
運(yùn)行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)造塊同樣都被拷貝進(jìn)了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)造塊同樣都被拷貝進(jìn)了字節(jié)碼init代碼塊中。Java的成員變量初始化和構(gòu)造塊也是按聲明順序執(zhí)行。不同的是,Java的構(gòu)造函數(shù)代碼始終放在了字節(jié)碼init代碼塊的后面。
字節(jié)碼的init初始化塊,其實(shí)就是類的真正的構(gòu)造函數(shù)。Kotlin多個init代碼塊都是按照順序拷貝進(jìn)了字節(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 package屬性、package name和Application ID三者的聯(lián)系及區(qū)別
這篇文章主要介紹了Android package屬性、package name和Application ID三者的聯(lián)系及區(qū)別的相關(guān)資料,需要的朋友可以參考下2016-12-12Android編程計算函數(shù)時間戳的相關(guān)方法總結(jié)
這篇文章主要介紹了Android編程計算函數(shù)時間戳的相關(guān)方法,結(jié)合實(shí)例形式總結(jié)分析了Android Java、Native、Kernel時間戳計算相關(guān)操作技巧,需要的朋友可以參考下2017-05-05android組件SwipeRefreshLayout下拉小球式刷新效果
這篇文章主要為大家詳細(xì)介紹了android組件SwipeRefreshLayout下拉小球式刷新效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-02-02詳解android 視頻圖片混合輪播實(shí)現(xiàn)
這篇文章主要介紹了android 視頻圖片混合輪播實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05ListView異步加載圖片實(shí)現(xiàn)思路(優(yōu)化篇)
關(guān)于listview的異步加載,網(wǎng)上其實(shí)很多示例了,中心思想都差不多,不過很多版本或是有bug,或是有性能問題有待優(yōu)化,下面就讓在下闡述其原理以探索個中奧秘2013-04-04Android 利用ViewPager+GridView實(shí)現(xiàn)首頁導(dǎo)航欄布局分頁效果
用ViewPager+GridView實(shí)現(xiàn)首頁導(dǎo)航欄布局分頁效果來實(shí)現(xiàn)的效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2016-10-10Android ListView分頁簡單實(shí)現(xiàn)
這篇文章主要介紹了Android ListView分頁簡單實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-06-06