Kotlin伴随对象的初始化方法示例讲解
作者:昉钰 发布时间:2022-07-24 05:53:06
在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


猜你喜欢
- Session具有以下特点: (1)Session中的数据保存在服务器端; (2)Session中可以保存任意类型的数据; (2)Sessi
- 在程序开发过程中,如何会使用键盘来完成所有的操作,会提高开发的速度。所以说,灵活的掌握并应用visual studio 的键盘快捷键非常重要
- 1、锁优化在JDK6之前,通过synchronized来实现同步效率是很低的,被synchronized包裹的代码块经过javac编译后,会
- 一、首先我们先创建一个Maven项目把我们需要的包先准备好 1.打开pom.xml文件引入依赖,以下是整个pom.xml文件<
- 四道Java基础题,你能对几道?一、==符的使用首先看一段比较有意思的代码Integer a = 1000,b=1000; Integer
- 文件的上传及下载功能是开发人员在日常应用及编程开发中经常会遇到的。正好最近开发需要用到此功能,虽然本人是 Android 开发人员,但还是业
- 时间轴,顾名思义就是将发生的事件按照时间顺序罗列起来,给用户带来一种更加直观的体验。京东和淘宝的物流顺序就是一个时间轴,想必大家都不陌生,如
- 公司项目中经常设计到串口通信,TCP通信,而且大多都是实时的大数据的传输,然后大家都知道协议通讯肯定涉及到什么,封包、拆包、粘包、校验……什
- 本文实例讲述了C#控制台下多线程实现方法。分享给大家供大家参考。具体如下:class Program{ static void
- 使用wpf程序常常会出现一个问题,那就是内存占用过高,使用wpf的程序功能越复杂往往用着用着内存就本着90往上去了。一方面wpf本身是一个u
- string fileExt = Path.GetExtension(excelPath);string conn = "&quo
- Java 执行 JS 脚本工具用途:为了便于系统扩展,提供了 JS 脚本的功能,可以通过在系统中执行脚本来获得更复杂的功能。例如:系统提供了
- 不啰嗦,上菜 QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.se
- 本文实例为大家分享了java日期时间基本操作方法,供大家参考,具体内容如下1. 获得Calendar实例:Calendar c = Cale
- Java语言是简单的:Java语言的语法与C语言和C++语言很接近,使得大多数程序员很容易学习和使用。另一方面,Java丢弃了C++中很少使
- 在协程启动模式中已经知道async是可以返回结果的,但是只返回一个,那么在复杂场景下就会不够用了,所以Channel就出现了。1.认识Cha
- 1.pom.xml<?xml version="1.0" encoding="UTF-8"?&
- 本文实例为大家分享了java 利用Socket实现SMTP协议发送邮件的具体代码,供大家参考,具体内容如下package mail;impo
- 前言随着微软对C#不断发展和更新,C#中对于数组操作的方式也变得越来越多样化。以往要实现过滤数组中的空字符串,都是需要实行循环的方式来排除和
- 网上的教程大都是手动通过protoc编译, 比较难用给当前工程添加"Google.Protobuf"和"Grp