Talk about the constructor of kotlin

foreword

I started to write projects after reading the comparative syntax of Java and kotlin before. I can get started with the definition of variables and methods, class inheritance, and interface implementation. Then when I suddenly need to customize View, I find that I will not repeat Write a constructor, and then have to go online to search how to overload the constructor, and found some points that need attention, record it.

I will first write down some methods of the constructors that I have organized that need to be recorded. If you can know what these are, then there is no need to read this article.

class Person {}

class Person1() {}

class Person2 private constructor() {}

class Person3(_name: String, _age: Int) {
    fun showName() {
//        println(_name)
    }
}

class Person4(val name: String, val age: Int) {
    fun showName() {
        println(name)
    }
}

class Person5(_name: String, _age: Int) {
    var mName: String? = null

    init {
        val name = _name
        val age = _age
        mName = _name
    }
}

class Person6(val name: String, val age: Int = 18) {}

class Person8(_name: String, _age: Int) {
    constructor(name: String) : this(name, 18)
}


class Person7 @JvmOverloads constructor(val name: String, val age: Int = 18) {}

class Person9 @JvmOverloads constructor(
    _name: String,
    _age: Int = 18,
    _height: Int = 170,
    _weight: Int = 60,
    _sex: Char = '男'
) {}
  • Kotlin's class definition comes with an empty constructor by default. When instantiating an object, you need to call the empty constructor through Person().
  • constructor is the keyword of the constructor. When declaring a class, the main constructor can omit the keyword, and private can be added before the keyword to make the constructor privatized

public final class Person {
}
public final class Person1 {
}
public final class Person2 {
   private Person2() {
   }
}
Person person = new Person();
Person1 person1 = new Person1();
//'Person2()' has private access in 'xxx.Person2'
//Person2 person2 = new Person2();

  • The parameters declared in the main constructor cannot be accessed as global variables in the class if they are not declared with the val/var keyword
  • Variables declared without the val/var keyword can be accessed in the init{} code block, and thus assigned to global variables in the class. The scope of local variables declared in the init{} code block is only in the function stack of init In the class, the rest of the class cannot be accessed

//不使用val/var声明构造函数参数,不会生成类里面的全局属性
public final class Person3 {
   public final void showName() {
   }

   public Person3(@NotNull String _name, int _age) {
      super();
   }
}

//使用了val/var声明的构造函数参数,会在类里面声明成员属性
public final class Person4 {
   @NotNull
   private final String name;
   private final int age;

   public final void showName() {
      String var1 = this.name;
      boolean var2 = false;
      System.out.println(var1);
   }

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final int getAge() {
      return this.age;
   }

   public Person4(@NotNull String name, int age) {
      super();
      this.name = name;
      this.age = age;
   }
}

//init代码块类似于主构造函数的函数体
public final class Person5 {
   @Nullable
   private String mName;

   @Nullable
   public final String getMName() {
      return this.mName;
   }

   public final void setMName(@Nullable String var1) {
      this.mName = var1;
   }

   public Person5(@NotNull String _name, int _age) {
      super();
      this.mName = _name;
   }
}
  • The variable declaration of the kotlin constructor can be assigned a default value. This is a feature that java does not have. In kotlin, the constructor is declared through the constructor. The code compiled by javac will have function overloading so that Java can call the constructor with default parameters. You can also directly compile the overloaded constructor through @JvmOverloads

//编译后生成一个两个参数的构造方法,和一个用于kotlin调用缺省参数的填默认值的方法
public final class Person6 {
   @NotNull
   private final String name;
   private final int age;

   public Person6(@NotNull String name, int age) {
      super();
      this.name = name;
      this.age = age;
   }

   // $FF: synthetic method
   public Person6(String var1, int var2, int var3, DefaultConstructorMarker var4) {
      if ((var3 & 2) != 0) {
         var2 = 18;
      }
      this(var1, var2);
   }
}

//java中没有调用缺省参数的构造方法
//'Person6(java.lang.String, int)' in 'xxx.Person6' cannot be applied to '(java.lang.String)'
// Person6 person6 = new Person6("bitibaba");
val p6 = Person6("bitibab")//kotlin可以直接使用这个特性

//通过@JvmOverloads会生成多个构造函数,Java也可以使用缺省参数的方式进行调用
public final class Person7 {
   @NotNull
   private final String name;
   private final int age;

   @JvmOverloads
   public Person7(@NotNull String name, int age) {
      Intrinsics.checkNotNullParameter(name, "name");
      super();
      this.name = name;
      this.age = age;
   }

   // $FF: synthetic method
   public Person7(String var1, int var2, int var3, DefaultConstructorMarker var4) {
      if ((var3 & 2) != 0) {
         var2 = 18;
      }

      this(var1, var2);
   }

   @JvmOverloads
   public Person7(@NotNull String name) {
      this(name, 0, 2, (DefaultConstructorMarker)null);
   }
}

//通过一个参数,另一个默认参数不传可以实例化对象
 Person7 person7 = new Person7("bitibaba");

//直接显示的声明一个次构造函数,参数如果过多,没有@JvmOverloads方便
public final class Person8 {
   public Person8(@NotNull String _name, int _age) {
      super();
   }

   public Person8(@NotNull String name) {
      this(name, 18);
   }
}
  • In Java, when there are too many constructor parameters, the corresponding parameters need to be passed in order. In kotlin, it is not necessary to assign values ​​​​in the order of parameters by displaying assignments, which is more convenient.

How to realize the default parameters

The kotlin default parameter feature above is very convenient to use, and it is also very convenient to assign values ​​​​by ignoring the order of parameters through the parameter name, and it is also very simple to implement

class Person9(
    _name: String,
    _age: Int = 18,
    _height: Int = 170,
    _weight: Int = 60,
    _sex: Char = '男'
) {}

//使用kotlin进行实例化
val p1 = Person9("xiaobiti")
val p2 = Person9("xiaobiti",12)
val p3 = Person9("xiaobiti", 12,155)
val p4 = Person9("xiaobiti", 12,155,45)
val p5 = Person9("xiaobiti", 12,155,45,'女')
val p6 = Person9("xiaobiti", _age = 12, _sex = '女')

//编译后
public final class Person9 {
   public Person9(@NotNull String _name, int _age, int _height, int _weight, char _sex) {
      super();
   }

   // $FF: synthetic method
   public Person9(String var1, int var2, int var3, int var4, char var5, int var6, DefaultConstructorMarker var7) {
      if ((var6 & 2) != 0) {
         var2 = 18;
      }

      if ((var6 & 4) != 0) {
         var3 = 170;
      }

      if ((var6 & 8) != 0) {
         var4 = 60;
      }

      if ((var6 & 16) != 0) {
         var5 = 30007;
      }

      this(var1, var2, var3, var4, var5);
   }
}

new Person9("xiaobiti", 0, 0, 0, '\u0000', 30, (DefaultConstructorMarker)null);
new Person9("xiaobiti", 12, 0, 0, '\u0000', 28, (DefaultConstructorMarker)null);
new Person9("xiaobiti", 12, 155, 0, '\u0000', 24, (DefaultConstructorMarker)null);
new Person9("xiaobiti", 12, 155, 45, '\u0000', 16, (DefaultConstructorMarker)null);
new Person9("xiaobiti", 12, 155, 45, '女');
new Person9("xiaobiti", 12, 0, 0, '女', 12, (DefaultConstructorMarker)null);

By looking at the compiled code, it is found that when using the characteristics of default parameters, there is no @JvmOverloads annotation, only a constructor with full parameters and another constructor are generated, and the constructor calls with default parameters are finally called. The generated $FF: synthetic method method, after a series of if checks in this method , still calls the constructor method with full parameters, then this if judges what it is doing, and performs the & operation through the last parameter of var6 , Determine whether the corresponding location is set

There will be a serial number value for the parameters of the constructor, which is the nth power of 2. This n is the position of the parameter. Through the AND operation, it is very good to use a flag to judge which parameters have no set value, so as to set the corresponding Defaults

This is easy to understand. For example, a constructor has n parameters. If each parameter has a default value, then calling the constructor will have two situations of assignment/no assignment for each parameter in each position, expressed in binary. Then perform the & operation to determine whether to assign a value

class Person9(
    _name: String,// 2^0=1
    _age: Int = 18, //2^1=2
    _height: Int = 170,//2^2=4
    _weight: Int = 60,//2^3=8
    _sex: Char = '男'//2^4=16
) {}
//举个栗子
//类似这个调用,缺省了第二位的参数,那就是00010
val p7 = Person9("xiaobiti", _height = 155, _weight = 45, _sex = '女')

  // $FF: synthetic method
public Person9(String var1, int var2, int var3, int var4, char var5, int var6, DefaultConstructorMarker var7) {
     //2的2进制就是10-> 00010&10=00010  !=0 判断命中,第二个参数_age就赋值默认参数18
      if ((var6 & 2) != 0) {
         var2 = 18;
      }

      if ((var6 & 4) != 0) {
         var3 = 170;
      }

      if ((var6 & 8) != 0) {
         var4 = 60;
      }

      if ((var6 & 16) != 0) {
         var5 = 30007;
      }

      this(var1, var2, var3, var4, var5);
   }
}

//如下就能知道
//00100=4
val p8 = Person9("xiaobiti", _age = 12, _weight = 45, _sex = '女')
//01000=8
val p9 = Person9("xiaobiti", _age = 12, _height = 155, _sex = '女')
//10000=16
val p10 = Person9("xiaobiti", _age = 12, _height = 155, _weight = 45)

//编译后
new Person9("xiaobiti", 12, 0, 45, '女', 4, (DefaultConstructorMarker)null);
new Person9("xiaobiti", 12, 155, 0, '女', 8, (DefaultConstructorMarker)null);
new Person9("xiaobiti", 12, 155, 45, '\u0000', 16, (DefaultConstructorMarker)null);

//回头看前面的栗子
val p1 = Person9("xiaobiti") //11110
val p2 = Person9("xiaobiti", 12) // 11100
val p3 = Person9("xiaobiti", 12, 155) // 11000
val p4 = Person9("xiaobiti", 12, 155, 45)// 10000

//验证反编译后
new Person9("xiaobiti", 0, 0, 0, '\u0000', 30, (DefaultConstructorMarker)null);
new Person9("xiaobiti", 12, 0, 0, '\u0000', 28, (DefaultConstructorMarker)null);
new Person9("xiaobiti", 12, 155, 0, '\u0000', 24, (DefaultConstructorMarker)null);
new Person9("xiaobiti", 12, 155, 45, '\u0000', 16, (DefaultConstructorMarker)null);

Kotlin is also the blessing of the compiler, allowing the written default parameters to identify the position of the missing parameter during compilation, and then assign the binary value of the corresponding position to 1 to generate a matching value. Through a series of if judgments, the missing parameter can be replaced. Assign the value of the value to the default value
Through the above content, when customizing the View, you can overload the constructor through annotations

//传统的java写法
public class MyJavaView extends View {

    public MyJavaView(Context context) {
        this(context,null);
    }

    public MyJavaView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public MyJavaView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}
//会重写构造函数,并且调用多参数的构造函数

//kotlin写法,加上注解
class MyKtView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) :View(context, attrs, defStyleAttr) {
}

//反编译后
public final class MyKtView extends View {
   @JvmOverloads
   public MyKtView(@NotNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
   }

   // $FF: synthetic method
   public MyKtView(Context var1, AttributeSet var2, int var3, int var4, DefaultConstructorMarker var5) {
      if ((var4 & 2) != 0) {
         var2 = (AttributeSet)null;
      }

      if ((var4 & 4) != 0) {
         var3 = 0;
      }

      this(var1, var2, var3);
   }

   @JvmOverloads
   public MyKtView(@NotNull Context context, @Nullable AttributeSet attrs) {
      this(context, attrs, 0, 4, (DefaultConstructorMarker)null);
   }

   @JvmOverloads
   public MyKtView(@NotNull Context context) {
      this(context, (AttributeSet)null, 0, 6, (DefaultConstructorMarker)null);
   }
}


summary

These are the points I didn’t understand after reading the article about converting Java to kotlin. If you pass by, you are welcome to comment and discuss. Thank you

Guess you like

Origin blog.csdn.net/liujun3512159/article/details/127815997