Kotlin 資料類

在這個教程中,我們將介紹 Kotlin Data Class。如果您還沒有閱讀過Kotlin Classes文章,我們建議您在繼續之前先閱讀一下。

Kotlin Data Class

在 Java 中,為您的 POJO 數據類編寫成千行的代碼讓您感到疲倦了嗎?每個 Java 程序員在某個階段都必須注意到他們需要為只需要存儲一些數據的類編寫多少行代碼。讓我們看一下一個Book.java的 POJO 類是什麼樣子:

public class Book {

    private String name;
    private String authorName;
    private long lastModifiedTimeStamp;
    private float rating;
    private int downloads;


    public Book(String name, String authorName, long lastModified, float rating, int downloads) {
        this.name = name;
        this.authorName = authorName;
        this.lastModifiedTimeStamp = lastModified;
        this.rating = rating;
        this.downloads = downloads;
    }

    public String getName() {
        return name;
    }

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

    public String getAuthorName() {
        return authorName;
    }

    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }

    public long getLastModifiedTimeStamp() {
        return lastModifiedTimeStamp;
    }

    public void setLastModifiedTimeStamp(long lastModifiedTimeStamp) {
        this.lastModifiedTimeStamp = lastModifiedTimeStamp;
    }

    public float getRating() {
        return rating;
    }

    public void setRating(float rating) {
        this.rating = rating;
    }

    public int getDownloads() {
        return downloads;
    }

    public void setDownloads(int downloads) {
        this.downloads = downloads;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Book that = (Book) o;

        if (downloads != that.downloads)
            return false;
        if (name != null ? !name.equals(that.name) :
                that.name != null) {
            return false;
        }
        return authorName != null ?
                authorName.equals(that.authorName) :
                that.authorName == null;

    }

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

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + authorName + '\'' +
                ", lastModifiedTimestamp='" + lastModifiedTimeStamp + '\'' +
                ", rating='" + rating + '\'' +
                ", downloads=" + downloads +
                '}';
    }
}

哇!僅僅用於存儲 5 個字段的對象就需要 96 行代碼。除了有 getter 和 setter、toString()equals()hashCode() 方法之外,我們在這裡並沒有做太多事情。根據我們的實踐,我們需要創建 POJO 類以實現乾淨的架構和代碼分離,因為每個項目都需要在某處存儲數據。這可能會增加樣板代碼。這就是 Kotlin 出手相助的地方,它使用 Data Classes 來減少樣板代碼。上述的 POJO 類在 Kotlin 中可以這樣寫:

data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

就是這樣。Kotlin 將 96 行的 Java 代碼轉換為一行代碼。這就是 Kotlin 在您的項目中減少樣板代碼的方式!

創建 Kotlin Data Class

以下是創建 Kotlin Data class 的要求。

  • 你需要在類名後面加上關鍵字 data
  • 主要的構造函數需要至少有一個參數。
  • 主要構造函數的每個參數都必須被賦予 valvar。這在一般的類中並不是必須的。
  • Data class 不能使用 abstractopensealedinner

Kotlin Data Class 的內建方法

Kotlin Data class 會自動為你創建以下函數。

  • equals()hashCode()
  • toString() 的格式為 "Book(name=JournalDev, authorName=Anupam)"
  • 為每個指定的參數創建 componentN() 函數。這被稱為解構聲明。
  • copy()

Kotlin 資料類別的特性

以下是資料類別所提供的一些特性。

  • 要建立一個無參數的建構子,請為主要建構子中的每個參數指定預設值。

  • 資料類別允許子類別化(不需要使用關鍵字 open)。

  • 您可以為函式 equals()hashCode()toString() 提供明確的實作。

  • 不允許為函式 copy()componentN() 提供明確的實作。

  • 我們可以通過在建構子中指定可見性修飾符來控制 getters 和 setters 的可見性,如下所示。

    data class Book(var name: String,private var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)
    
  • val參數不會有隱式定義的setter(也不能顯式定義!)。

數據類中的默認參數和命名參數

以下是我們的數據類:

data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

沒有為任何參數設置默認值。因此,我們需要在實例化時為每個參數設置一個參數,如下所示。

fun main(args: Array<String>) {
val book = Book("Android Tutorials","Anupam", 1234567, 4.5f, 1000)
}

讓我們設置一些默認參數,看看實例化如何變化。


data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)
fun main(args: Array<String>) {
var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    book = Book("Kotlin")
    book = Book("Swift",downloads = 500)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    book = Book("Python","Shubham",rating = 5f)

}

我們可以只設置非默認參數和我們希望設置的參數,使用命名參數。使用命名參數,我們可以通過明確指定參數名後跟=來將第5個參數設置為第二個參數。這樣生活就變得更簡單了!

Kotlin數據類toString()方法

toString()方法是隱式創建的,並打印實例的參數名和標籤,如下所示。

data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)


fun main(args: Array) {

    var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)
    book = Book("Kotlin")
    println(book)
    book = Book("Swift",downloads = 500)
    println(book)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    println(book.toString())
    book = Book("Python","Shubham",rating = 5f)
    println(book.toString())


}

//以下內容印在控制台上。
//Book(name=Android教程,authorName=Anupam,lastModified=1234567,rating=4.5,downloads=1000)
//Book(name=Kotlin,authorName=Anupam,lastModified=1234567,rating=5.0,downloads=1000)
//Book(name=Swift,authorName=Anupam,lastModified=1234567,rating=5.0,downloads=500)
//Book(name=Java,authorName=Pankaj,lastModified=1234567,rating=5.0,downloads=1000)
//Book(name=Python,authorName=Shubham,lastModified=1234567,rating=5.0,downloads=1000)

注意print 函數會隱式添加 toString()。

Kotlin資料類別的copy()方法

Copy 函數用於創建資料類別的實例的副本,並修改其中的一些屬性。建議在資料類別的構造函數中使用 val 參數,以使用實例的不可變屬性。在多線程應用程序中,使用不可變物件更容易。因此,為了僅改變少數屬性而創建不可變物件的副本,可以使用 copy() 函數。

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)

    val newBook = book.copy(name = "Kotlin")
    println(newBook)
}
//以下內容印在控制台上。
//Book(name=Android教程,authorName=Anupam,lastModified=1234567,rating=4.5,downloads=1000)
//Book(name=Kotlin,authorName=Anupam,lastModified=1234567,rating=4.5,downloads=1000)

Kotlin Data Class equals() and hashCode()

hashCode() 方法返回對象的哈希碼。如果兩個對象相等,則 hashCode() 會產生相同的整數結果。因此,equals() 如果 hashCode() 相等,則返回 true,否則返回 false。

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println("Hashcode is ${book.hashCode()}")

    val newBook = book.copy(name = "Kotlin")
    println("Hashcode is ${newBook.hashCode()}")

    val copyBook = book.copy()
    println("Hashcode is ${copyBook.hashCode()}")


    if(copyBook.equals(book))
        println("copyBook and book are equal")

    if(!book.equals(newBook))
        println("newBook and book are NOT equal")

}

//以下在控制台中打印。
//Hashcode 是 649213087
//Hashcode 是 1237165820
//Hashcode 是 649213087
//copyBook 和 book 是相等的
//newBook 和 book 不相等

第一個和第三個對象的哈希碼相等,因此它們是相等的。 注意:在 Kotlin 中,equals() 方法等同於 ==

Destructuring Declarations

componentN() 函数讓我們可以按照指定的順序訪問構造函數中指定的每個參數。N 是構造函數中的參數數量。

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    println(book.component1()) //Android tutorials
    println(book.component2()) //Anupam
    println(book.component3()) //1234567
    println(book.component4()) //4.5
    println(book.component5()) //1000
    
}

解構聲明允許我們從類對象中作為屬性訪問參數,如下所示。

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book
}

注意:如果在任何参数上设置了私有等可见性修饰符,则无法在上述函数中访问。

data class Book(val name: String,private val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book //This won't compile since authorName is private
}

这就是有关Kotlin数据类的快速概述。参考资料:Kotlin文档

Source:
https://www.digitalocean.com/community/tutorials/kotlin-data-class