美文网首页
Kotlin init块和构造函数及伴生对象的执行顺序

Kotlin init块和构造函数及伴生对象的执行顺序

作者: 头秃到底 | 来源:发表于2024-04-06 18:12 被阅读0次

Kotlin为开发者提供了主构造函数和次构造函数外,还提供了init代码块,供开发者做一些初始化操作。
那么kotlin init代码块是什么时候执行的那,与构造方法以及伴生对象一起使用时代码执行顺序又是怎样的那?
通过一个例子来看一下。 先来看看kotlin中init代码块和构造方法的执行顺序

class Person() {
 
    /*属性*/
    private var gender: Boolean = true
 
    /*次构造函数*/
    constructor(name: String, gender: Boolean): this() {
        println("Person constructor")
    }
 
    /*初始化代码块*/
    init {
        println("Person init 1, gender:${gender}")
    }
 
    /*初始化代码块*/
    init {
        println("Person init 2")
    }
 
}

上面是一个简单的Person类,我们在类中写了一个次构造方法、两个init代码块和一个属性 此时,当我们调用Person("xxxxx", false)时,Person类中代码的执行顺序是什么样的? 打印结果如下

Person init 1, gender:true
Person init 2
Person constructor

可以看到,首先会按顺序执行类中init代码块,然后再执行构造方法里代码,并且我可以在init代码块中使用类声明的属性

下面我们可以将kotlin变成成字节码,然后再反编译成java代码。[具体可以通过AS中tools工具栏kotlin的菜单工具进行转换。] kotlin代码反编译成java代码:

public final class Person {
   private boolean gender;
 
   public Person() {
      this.gender = true;
      String var1 = "Person init 1, gender:" + this.gender;
      boolean var2 = false;
      System.out.println(var1);
      var1 = "Person init 2";
      var2 = false;
      System.out.println(var1);
   }
 
   public Person(@NotNull String name, boolean gender) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      this();
      String var3 = "Person constructor";
      boolean var4 = false;
      System.out.println(var3);
   }
}

可以看到,实际上init代码块中的代码会按顺序放在构造函数中,构造函数中原来的代码会在init代码后面执行。 我们再来给类中加入伴生对象来看看

class Person() {
    companion object {
         val instance by lazy {
             Person("yyyyyyy", false)
         }

         /*伴生对象中的初始化代码*/
         init {
             println("Person companion init 1")
         }

         init {
             println("Person companion init 2")
         }
     }
 
 
    /*属性*/
    private var gender: Boolean = true
 
    /*次构造函数*/
    constructor(name: String, gender: Boolean) : this() {
        println("Person constructor")
    }
 
    /*初始化代码块*/
    init {
        println("Person init 1, gender:${gender}")
    }
 
    /*初始化代码块*/
    init {
        println("Person init 2")
    }
 
}

加入伴生对象后,那肯定就是伴生对象中的代码先执行了。
我们调用一下Person.instance来看一下结果:

Person companion init 1
Person companion init 2
///后面是instance懒加载的执行时的调用
Person init 1, gender:true
Person init 2
Person constructor

首先,伴生对象中的代码是在类加载时就会执行,也就说当我们代码中出现Person词语的时候,伴生对象中的代码就开始执行了,此时会先顺序的执行伴生对象中的init代码块,但是由于instance是懒加载的,所以只有当我们代码出现Person.instance时,才会执行instance中委托的代码。
此时会去调用指定的构造函数,而执行构造函数时就和最上面的那种执行顺序是一致的了,先执行类中的init代码块,再执行构造函数原本的代码。

下面看一下反编译过后的java代码:

public final class Person {
   private boolean gender;
   @NotNull
   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 1, gender:" + this.gender;
      boolean var2 = false;
      System.out.println(var1);
      var1 = "Person init 2";
      var2 = false;
      System.out.println(var1);
   }
 
   public Person(@NotNull String name, boolean gender) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      this();
      String var3 = "Person constructor";
      boolean var4 = false;
      System.out.println(var3);
   }
 
   static {
      instance$delegate = LazyKt.lazy((Function0)null.INSTANCE);
      String var0 = "Person companion init 1";
      boolean var1 = false;
      System.out.println(var0);
      var0 = "Person companion init 2";
      var1 = false;
      System.out.println(var0);
   }
 
   @Metadata(
      mv = {1, 1, 15},
      bv = {1, 0, 3},
      k = 1,
      d1 = {"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\b\u0005\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002R\u001b\u0010\u0003\u001a\u00020\u00048FX\u0086\u0084\u0002¢\u0006\f\n\u0004\b\u0007\u0010\b\u001a\u0004\b\u0005\u0010\u0006¨\u0006\t"},
      d2 = {"LPerson$Companion;", "", "()V", "instance", "LPerson;", "getInstance", "()LPerson;", "instance$delegate", "Lkotlin/Lazy;", "LeetCode"}
   )
   public static final class Companion {
      // $FF: synthetic field
      static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(Person.Companion.class), "instance", "getInstance()LPerson;"))};
 
      @NotNull
      public final Person getInstance() {
         Lazy var1 = Person.instance$delegate;
         Person.Companion var2 = Person.Companion;
         KProperty var3 = $$delegatedProperties[0];
         boolean var4 = false;
         return (Person)var1.getValue();
      }
 
      private Companion() {
      }
 
      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
   
}

那如果伴生对象里的instance不是懒加载的

class Person() {
    companion object {
        val instance = Person("zzzzz", false)
 
 
        /*伴生对象中的初始化代码*/
        init {
            println("Person companion init 1")
        }
 
        init {
            println("Person companion init 2")
        }
    }
    
     /*属性*/
    private var gender: Boolean = true
 
    /*次构造函数*/
    constructor(name: String, gender: Boolean) : this() {
        println("Person constructor")
    }
 
    /*初始化代码块*/
    init {
        println("Person init 1, gender:${gender}")
    }
 
    /*初始化代码块*/
    init {
        println("Person init 2")
    }
 
}

调用Person.instance结果如下:

//伴生对象中的 构造Person对象的Person实例instance的log
Person init 1, gender:true
Person init 2
Person constructor
//伴生对象中后面的 init代码
Person companion init 1
Person companion init 2

相关文章

  • kotlin中构造及初始化

    1 Kotlin中init代码块和构造方法以及伴生对象中代码的调用时机及执行顺序https://blog.csdn...

  • 2019-02-23

    Kotlin 中构造顺序 结果Chen1Chen12 构造函数的执行顺序①先执行值域的直接初始化②然后执行init...

  • Kotlin-类的init代码块、构造函数、伴生对象执行顺序探究

    得出结论 伴生对象 > 初始化代码块 > 构造函数(先>后) 代码验证 伴生对象的作用 通过的 Coffee.pl...

  • Kotlin类相关

    kotlin主构造函数代码块和静态代码块 在安卓自定义View的时候我们有多个构造函数重载 多个init块,执行顺...

  • kotlin-第三章(类与对象)

    构造函数 访问修饰符 伴生对象 单例类 动态代理 kotlin中特有的类 09:kotlin的构造函数 kotli...

  • Kotlin 类和对象

    Kotlin 类可以包含:构造函数和初始化代码块(init)、函数、属性、嵌套类和内部类、对象声明 1.使用关键字...

  • 类和对象

    Kotlin 类和对象类定义Kotlin 类可以包含:构造函数和初始化代码块、函数、属性、内部类、对象声明。Kot...

  • PostConstruct注解

    PostConstruct在构造函数之后执行,init()方法之前执行;他是Java自己的注解,对象被构造前执行,...

  • Kotlin 类和对象

    原文地址:Kotlin 类和对象 一、类定义 Kotlin 类可以包含:构造函数、初始化代码块、函数、属性、内部类...

  • Kotlin-构造函数(2)- 构造函数以及init执行顺序

    例子 注释1:主构造函数,数量<=1,如果都没有定义主、次构造函数,那么就会有一个默认无参的构造函数可以调用; 注...

网友评论

      本文标题:Kotlin init块和构造函数及伴生对象的执行顺序

      本文链接:https://www.haomeiwen.com/subject/hktztjtx.html