網(wǎng)站首頁 編程語言 正文
之前寫了一篇文章,從Java語法的角度分析了Kotlin構造函數(shù)、成員變量初始化、init代碼塊三者的執(zhí)行順序:
Kotlin構造函數(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}") } }
調用InitOrderDemo(“hello”)
打印的結果如下:
First property: hello
First initializer block that prints hello
Second property: 5
Second initializer block that prints 5
可以看到執(zhí)行順序,是按照它們聲明的順序執(zhí)行。
將上面Koltin代碼轉成字節(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 }
可以看到上面的構造函數(shù)、成員變量初始化和init代碼塊,按照聲明都被放到了字節(jié)碼的init代碼塊中了。
字節(jié)碼的init初始化器其實就是類的構造函數(shù)。將Java代碼轉成字節(jié)碼也是存在init構造函數(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ù)打印結果如下:
This is init block
firstName=Steven
secondName=Jobs
將上面的JavaInit
類轉成字節(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類的成員變量初始化、構造函數(shù)、構造塊同樣都被拷貝進了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類的成員變量初始化、構造函數(shù)、構造塊同樣都被拷貝進了字節(jié)碼init代碼塊中。Java的成員變量初始化和構造塊也是按聲明順序執(zhí)行。不同的是,Java的構造函數(shù)代碼始終放在了字節(jié)碼init代碼塊的后面。
字節(jié)碼的init初始化塊,其實就是類的真正的構造函數(shù)。Kotlin多個init代碼塊都是按照順序拷貝進了字節(jié)碼的init初始化塊中,可以理解為它們是構造函數(shù)的組成部分。
Java和kotlin成員變量的初始化都是放到字節(jié)碼的init代碼塊中,也就是在構造函數(shù)中執(zhí)行的。
原文鏈接:https://blog.csdn.net/devnn/article/details/127620245
相關推薦
- 2022-09-03 Python標準庫time使用方式詳解_python
- 2022-12-23 react數(shù)據(jù)管理機制React.Context源碼解析_React
- 2022-10-06 一文掌握python中的時間包_python
- 2022-07-04 python如何處理matlab的mat數(shù)據(jù)_python
- 2022-07-30 react擴展6_renderProps
- 2024-01-13 SpringCloud Alibaba——Nacos1.x配置中心長輪詢機制
- 2022-04-03 Python?Flask?+?Redis?程序練習_python
- 2022-11-28 golang進程內(nèi)存控制避免docker內(nèi)oom_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支