網站首頁 編程語言 正文
在Java中我們知道靜態變量會在類加載時機的“初始化”階段得到賦值(編譯器會收集類中的靜態變量及靜態代碼塊,然后在類構造方法<clinit>()中執行,注意:這里不是實例構造方法),也就是真正運行程序中的代碼;執行完類構造方法之后才會執行我們熟悉的實例構造方法。
? 而在Kotlin中有所謂的伴隨對象,用過的同學都知道,它的功能類似于Java中的靜態變量,那它又是什么時候初始化的呢?來看一個例子,代碼如下:
package com.zfang.testapp
class KConstructTest(val first: String, val second: Int) {
init {// 111
println("KConstructTest init")
test(1)
}
companion object CC {
init { // 222
println("companion object init")
}
fun test(index: Int) {
println("test, index = $index")
}
}
}
一個簡單的kotlin類,里面包含一個伴隨對象CC,現在寫一個測試類來看一個標記111和222這兩個地方誰先初始化,測試代碼如下:
package com.zfang.testapp;
class Test {
public static void main(String[] args) {
KConstructTest test = new KConstructTest("ttt", 1);
KConstructTest.CC cc = test.CC;
}
}
一個簡單的Java測試類,入口中直接new了一個KConstructTest對象,下面是程序輸出:
companion object init
KConstructTest init
test, index = 1
從輸出結果中可以看出是伴隨對象的init代碼塊先執行了,然后才是主類中的init代碼塊執行。下面我們反編譯看下生存的java類是怎樣的。結果如下:
package com.zfang.testapp;
import kotlin.Metadata;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 7, 1},
k = 1,
d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0002\b\u0007\u0018\u0000 \u000b2\u00020\u0001:\u0001\u000bB\u0015\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005¢\u0006\u0002\u0010\u0006R\u0011\u0010\u0002\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\u0007\u0010\bR\u0011\u0010\u0004\u001a\u00020\u0005¢\u0006\b\n\u0000\u001a\u0004\b\t\u0010\n¨\u0006\f"},
d2 = {"Lcom/zfang/testapp/KConstructTest;", "", "first", "", "second", "", "(Ljava/lang/String;I)V", "getFirst", "()Ljava/lang/String;", "getSecond", "()I", "CC", "app_debug"}
)
public final class KConstructTest {
@NotNull
private final String first;
private final int second;
@NotNull
public static final KConstructTest.CC CC = new KConstructTest.CC((DefaultConstructorMarker)null);
@NotNull
public final String getFirst() {
return this.first;
}
public final int getSecond() {
return this.second;
}
public KConstructTest(@NotNull String first, int second) {//與主構造方法對應
Intrinsics.checkNotNullParameter(first, "first");
super();
this.first = first;
this.second = second;
String var3 = "KConstructTest init";//主類中的init代碼塊
System.out.println(var3);
CC.test(1);
}
static {//伴隨對象中的init代碼塊
String var0 = "companion object init";
System.out.println(var0);
}
@Metadata(
mv = {1, 7, 1},
k = 1,
d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\b\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u000e\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u0006¨\u0006\u0007"},
d2 = {"Lcom/zfang/testapp/KConstructTest$CC;", "", "()V", "test", "", "index", "", "app_debug"}
)
public static final class CC {//伴隨對象類
public final void test(int index) {
String var2 = "test, index = " + index;
System.out.println(var2);
}
private CC() {
}
// $FF: synthetic method
public CC(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
額,反編譯出來的Java代碼看上去有點多的樣子。不過邏輯還是很簡單的,主要以下幾點:
- 伴隨對象類編譯成了與Java相對應的靜態內部類(又叫內嵌類),并且伴隨對象中的init代碼塊編譯成了主類中的靜態代碼塊。
- 主類primary構造函數相應的就是Java類的構造函數,同時主類中的init代碼塊則編譯到了主構造函數中了。
根據以上分析則可以得出結論:
- 伴隨對象中的init代碼塊首先執行(因為它被編譯成主要的靜態代碼塊了,在類的初始化階段就會執行)。
- 然后才會執行主類中的Init代碼塊(此代碼塊被編譯到相應Java代碼中的實例構造方法里面了,執行完類構造方法之后才會執行實例構造方法)。
所以如果項目中對主類Init塊和伴隨對象init塊有初始化順序要求的就需要注意相應的邏輯了。
原文鏈接:https://blog.csdn.net/www586089/article/details/127983595
相關推薦
- 2022-09-19 Nginx最大連接數配置詳解_nginx
- 2022-05-13 類實例化 對象的內存模型 及 內存占用分析
- 2022-04-19 C語言庫函數qsort及bsearch快速排序算法使用解析_C 語言
- 2022-10-25 在IIS上部署Go?API項目_win服務器
- 2022-08-06 Android?無障礙全局懸浮窗實現示例_Android
- 2022-05-12 C語言的數組指針與函數指針詳解_C 語言
- 2022-04-09 SpringBoot上傳文件并配置本地資源映射來訪問文件
- 2023-01-30 Android自定義View模仿即刻點贊數字切換效果實例_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支