基础1

var / val 的区别

用kt文件转化成的java文件做对比

kotlin:

var a: Int = 0
val b: Int = 0

decompile之后的java:

public final class Kttest01Kt {
   private static int a;
   private static final int b = 0;

   public static final int getA() {
      return a;
   }

   public static final void setA(int var0) {
      a = var0;
   }

   public static final int getB() {
      return b;
   }
}

可以看到,最终的java代码中a/b区别:

  • a 没有final修饰,但是b有
  • a有get set方法,但是b没有set,只有get

属性和字段的区别

kotlin代码如下:

有一个Student类,3个成员变量,如果是如下写法,

class Student(name: String, age: Int, sex: Boolean) {
    var name = name


    var age = age
    var sex = sex

    init {
        println("主构造函数")
    }

    constructor(name: String) : this(name, 1, false) {

        println("次级构造函数,只给一个name参数")

    }

    constructor(name: String, age: Int) : this(name, age, false) {
        println("次级构造函数,只给name,age 2个参数")
    }

}

那么在 kotlin转成java之后,是这样子:

public final class Student {
   @NotNull
   private String name;
   private int age;
   private boolean sex;

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

   public final void setName(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "");
      this.name = var1;
   }

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

   public final void setAge(int var1) {
      this.age = var1;
   }

   public final boolean getSex() {
      return this.sex;
   }

   public final void setSex(boolean var1) {
      this.sex = var1;
   }

   public Student(@NotNull String name, int age, boolean sex) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.name = name;
      this.age = age;
      this.sex = sex;
      String var4 = "主构造函数";
      boolean var5 = false;
      System.out.println(var4);
      this.name = name;
      this.age = age;
      this.sex = sex;
   }

   public Student(@NotNull String name) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      this(name, 1, false);
      String var2 = "次级构造函数,只给一个name参数";
      boolean var3 = false;
      System.out.println(var2);
   }

   public Student(@NotNull String name, int age) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      this(name, age, false);
      String var3 = "次级构造函数,只给name,age 2个参数";
      boolean var4 = false;
      System.out.println(var3);
   }
}

上面一大段中,我们截取出以下部分

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

   public final void setName(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "");
      this.name = var1;
   }

解读:

  • private String name 才是java中的 Field 字段

  • 后面的get set方法是针对字段对外提供的访问方法

对比一下,如果我们在kotlin代码中把修改一下:

    private var _name: String = ""  //字段是内置的,这个叫字段,不对外公开

    //属性对外公开
    var name: String
        get() = "$_name ......."
        set(value) {
            if (value == null)
                this._name = ""
            else
                this._name = value
        }
    ....省略

此时decompile之后的java代码是:

   private String _name;

   @NotNull
   public final String getName() {
      return this._name + " .......";
   }

   public final void setName(@NotNull String value) {
      Intrinsics.checkParameterIsNotNull(value, "value");
      this._name = value;
   }

_name 是字段,getName和setName方法则是它的get set方法.

一句话总结:

kotlin中,类的成员属性自带 get set方法以及field , 也支持 完全自定义 field get set (就像上面这样).

Java中,写一个类成员变量需要很多行,但是 kotlin只需要一行,节省大量代码行数. 字段只用来存储值,属性除了存储值,还对外提供get set方法.

继承

open class Person(sex: Boolean) {
    open var sex: Boolean = sex
}


class Student(name: String, age: Int, sex: Boolean) : Person(sex) {

    var name: String = ""  //字段是内置的,这个叫字段,不对外公开
    var age = age
    override var sex = sex

    init {
        println("主构造函数")
        this.name = name
        this.age = age
        this.sex = sex
    }

    constructor(name: String) : this(name, 1, false) {

        println("次级构造函数,只给一个name参数")

    }

    constructor(name: String, age: Int) : this(name, age, false) {
        println("次级构造函数,只给name,age 2个参数")
    }

}
  • kotlin的类和属性默认是封闭的,如果想要让子类继承或者重写必须加上open关键字
  • 如果子类要重写父类的成员属性,必须父类加上open,子类同样属性加上override

lateinit 和 bylazy的区别

  • lateinit 修饰 var,而 by lazy 用在val上
  • lateinit不能 修饰java中的基本数据类型,也不能修饰可空类型。但是by lazy都可以
  ​ lateinit var intVar :Int //lateinit不能用在 基本(原始)数据类型上 (编译报错)

  ​ lateinit var nullableVar:String? // 也不能用在 可空类型上 (编译报错)

  ​ val strVal:String? by lazy { "ssss" } //但是by lazy可以  (编译正常)

  ​ val intVal:Int by lazy { 1 } // 但是 by lazy也可以 (编译正常)
  • lateinit 修饰的var可以赋值多次,by lazy 只能赋值一次, by lazy修饰val只能赋值一次

你可能感兴趣的:(基础1)