天天看點

Kotlin-10-資料類(data+lateinit+by lazy+field)

目錄

1、定義

2、kotlin資料類的優勢

3、kotlin資料類的限制

4、資料類的屬性

5、by lazy

6、field關鍵字

7、傳統JavaBean

1、定義

對應于Java中的資料類(JavaBean),kotlin的資料類是需要被data關鍵字所修飾的

  • 普通的資料類(進階版在第四小節)
data class Person1(var name: String, var age: Int) 
           

2、kotlin資料類的優勢

kotlin幫我們自動添加和重寫了JavaBean中以下方法,讓我們代碼更加的簡潔

setter()
      getter()      
      hashCode()
      equals()
      toString()
      copy()
      componentN()
           

3、kotlin資料類的限制

  •  被data關鍵字修飾的kotlin資料類預設是public final的,是以無法被繼承,也不能用open關鍵字(變成可繼承)修飾
  • 必須聲明主構造函數
  • 主構造函數必須要至少有一個參數
  • 主構造函數中的所有參數必須被标記為val或者var
  • 資料類不能有以下修飾符:abstract,inner,open,sealed

4、資料類的屬性

上面我們說過kotlin的資料類必須聲明主構造函數,并且至少得有一個參數,那麼我們不需要寫在構造函數參數裡的屬性應該怎麼寫呢?

注意:沒有寫在主構造函數的屬性,必須被lateinit關鍵字修飾或者初始化指派

注意:沒初始化指派的屬性,也可以通過by lazy文法來延遲指派

data class Person1(var name: String, var age: Int) {

    //用lateinit關鍵字修飾的屬性,可以沒有初始值,可以後期set、get
    lateinit var sex: String

    val sex1 by lazy {
        if (age > 20) "男" else "女"
    }

    //如果不加lateinit關鍵字,就必須被初始化指派
    var race="種族"

    //被val初始化的屬性,是無法被修改的,也就是無法被set
    val race1="漢族"

    /**
     * 1、上面的屬性,name、age、sex、race都是對set、get方法進行了省略,讓編譯器來自動添加set、get方法的
     * 2、當然我們也可以重寫set、get方法。來對set的值進行一定的封裝處理
     * 3、field相當于Java中的this.weight的含義,注意我們set方法中絕不不能調用自己this.weight
     * 否者就會出現無限的重複調用自己的死循環
     */

    var weight: Int = 0
        get() = field
        set(value) {
            field = value
        }

    var height: Int = 0
        set(value) {
            field = value + 10
        }

    val isMan:Boolean
        get() {
            return this.sex=="男"
        }

}
           

5、by lazy

被by lazy 修飾的變量有以下特點:

  • 必須用val修飾,不能使用var修飾
  • 在被首次調用的時候才會被指派,一旦被指派,後續就不能修改。
val sex1 by lazy {
        if (age > 20) "男" else "女"
    }

fun main() {
    val person=Person1("張三",18)
    println("person.sex1=${person.sex1}")
    person.age=21   //------------------------隻在第一次被調用的時候指派,後續指派也不會改變sex1的值
    println("person.sex2=${person.sex1}")

    val person1=Person1("張三",22)
    println("person.sex3=${person1.sex1}")
    //person.sex1="s" ------------------------------報錯,無法二次指派
}
//輸出結果
person.sex1=女
person.sex2=女
person.sex3=男
           

6、field關鍵字

 field類似于java裡的this.屬性名

var weight: Int = 0
        get() = field
        set(value) {
            field = value
        }
           

但是不能直接使用this.name會造成遞歸調用記憶體溢出的,  因為在set和get中是不允許有本身的局部變量的(例如如果你屬性名是name, 在set/get裡是不能有這個變量的), 因為屬性的調用也涉及到了set/get會造成遞歸調用, 是以要解決引用自身的問題, kotlin發明了field來解決這個問題

//這樣會無限的重複調用自己,導緻記憶體溢出
    var weight: Int = 0
        get() = field
        set(value) {
            this.weight=value
        }
           

7、傳統JavaBean

  • 首先看一下我們傳統的Java資料類(JavaBean)
public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (!(o instanceof Person))
            return false;

        Person person = (Person) o;

        if (age != person.age)
            return false;
        return name != null ? name.equals(person.name) : person.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}
           
  •    和kotlin類的輸出對比
fun main() {

    val person=Person();
    person.name = "張三"
    person.age = 18
    println(person)

    val person1=Person1("李四",20)
    println(person1)

}