1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package democlass Person () { private var gender: Boolean = true constructor (name: String, gender: Boolean ) : this () { println("constructor" ) } companion object { val instance by lazy { Person("yzq" ,false ) } init { println("companion init 1" ) } init { println("companion init 2" ) } } init { println("Person init 2,gender:${gender} " ) } init { println("Person init 1" ) } }
可以看到伴生对象里面的init
先执行了。我们看下反编译成Java长什么样,通过java文件我们可以很清楚的就知道为什么输出效果是上面那样的了。可以看到在对象里面,init代码块会被编译到构造函数里面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public final class Person { private boolean gender; private static final Lazy instance$delegate; public static final Person.Companion Companion = new Person.Companion((DefaultConstructorMarker)null ); public Person () { this .gender = true ; String var1 = "Person init 2,gender:" + this .gender; boolean var2 = false ; System.out.println(var1); var1 = "Person init 1" ; var2 = false ; System.out.println(var1); } public Person (@NotNull String name, boolean gender) { Intrinsics.checkNotNullParameter(name, "name" ); this (); String var3 = "constructor" ; boolean var4 = false ; System.out.println(var3); } static { instance$delegate = LazyKt.lazy((Function0)null .INSTANCE); String var0 = "companion init 1" ; boolean var1 = false ; System.out.println(var0); var0 = "companion init 2" ; var1 = false ; System.out.println(var0); } public static final class Companion { @NotNull public final Person getInstance () { Lazy var1 = Person.instance$delegate; Person.Companion var2 = Person.Companion; Object var3 = null ; boolean var4 = false ; return (Person)var1.getValue(); } private Companion () { } public Companion (DefaultConstructorMarker $constructor_marker) { this (); } } }
现在换种写法,instance
不用懒加载的方式创建,而是直接new。
1 2 val instance = Person("yzq" ,false )
反编译成java文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public final class Person { private boolean gender; @NotNull private static final Person instance = new Person("yzq" , false ); @NotNull public static final Person.Companion Companion = new Person.Companion((DefaultConstructorMarker)null ); public Person () { this .gender = true ; String var1 = "Person init 2,gender:" + this .gender; boolean var2 = false ; System.out.println(var1); var1 = "Person init 1" ; var2 = false ; System.out.println(var1); } public Person (@NotNull String name, boolean gender) { Intrinsics.checkNotNullParameter(name, "name" ); this (); String var3 = "constructor" ; boolean var4 = false ; System.out.println(var3); } static { String var0 = "companion init 1" ; boolean var1 = false ; System.out.println(var0); var0 = "companion init 2" ; var1 = false ; System.out.println(var0); } public static final class Companion { @NotNull public final Person getInstance () { return Person.instance; } private Companion () { } public Companion (DefaultConstructorMarker $constructor_marker) { this (); } } }
可以发现执行顺序变了。
我们可以发现在kotlin
里面通过companion object
修饰的代码块会被生成为静态变量。欧了。
还有一个好的案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class DS { var namedsa = "" constructor(name:String){ this .namedsa = name } init { println("我说${namedsa}" ) } companion object{ fun dsa () :DS { var s = DS("污泥" ) return s } } } fun main () { DS.dsa() }
他的输出结果是:我说
是不是很奇怪,污泥怎么不见了?现在来编译成java代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public final class DS { private String namedsa; public static final DS.Companion Companion = new DS.Companion((DefaultConstructorMarker)null ); @NotNull public final String getNamedsa () { return this .namedsa; } public final void setNamedsa (@NotNull String var1) { Intrinsics.checkNotNullParameter(var1, "<set-?>" ); this .namedsa = var1; } public DS (@NotNull String name) { Intrinsics.checkNotNullParameter(name, "name" ); super (); this .namedsa = "" ; String var2 = "我说" + this .namedsa; boolean var3 = false ; System.out.println(var2); this .namedsa = name; } public static final class Companion { @NotNull public final DS dsa () { return new DS("污泥" ); } private Companion () { } public Companion (DefaultConstructorMarker $constructor_marker) { this (); } } }
我们需要注意的知识点是:init的代码会插入到构造函数里面。他是优先于构造函数里面的任何代码。
好了,现在我在换中写法。构造函数的方式换下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class DS (name :String ) { init { println("我说${name}" ) } companion object{ fun dsa () :DS { var s = DS("污泥" ) return s } } } fun main () { DS.dsa() }
在猜猜,输出结果是啥?
结果是:我说污泥。
来看下java代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public final class DS { public static final DS.Companion Companion = new DS.Companion((DefaultConstructorMarker)null ); public DS (@NotNull String name) { Intrinsics.checkNotNullParameter(name, "name" ); super (); String var2 = "我说" + name; boolean var3 = false ; System.out.println(var2); } public static final class Companion { @NotNull public final DS dsa () { DS s = new DS("污泥" ); return s; } private Companion () { } public Companion (DefaultConstructorMarker $constructor_marker) { this (); } } }
可以看到这样写的话,输出的name直接走的是构造函数里面的name,比起之前的写法,少了一个this.namedsa的赋值操作,所以就出现了两个不同的输出情况。