Kotlin数据类

在本教程中,我们将介绍 Kotlin 数据类。如果您还没有阅读过 Kotlin Classes 帖子,我们建议在继续之前先这样做。

Kotlin 数据类

你是否厌倦了为 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 来解救我们。Data Classes 是 Kotlin 对减少样板代码的答案。上面的 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 数据类

以下是创建 Kotlin 数据类的要求。

  • 您需要使用关键字data来追加类
  • 主构造函数至少需要有一个参数。
  • 主构造函数的每个参数必须分配valvar。这与普通类不同,普通类中指定valvar并非强制性要求。
  • 数据类不能附加abstractopensealedinner

Kotlin 数据类内置方法

Kotlin 数据类会自动生成以下函数。

  • equals()hashCode()
  • toString() 的形式为 "Book(name=JournalDev, authorName=Anupam)"
  • componentN() 函数,用于按指定顺序的每个参数的解构声明。这称为解构声明。
  • copy()

Kotlin数据类特性

以下是数据类提供的一些特性。

  • 要创建一个无参构造函数,请为主构造函数中的每个参数指定默认值。

  • 数据类允许子类化(无需提及关键字open)。

  • 您可以为equals() hashCode()toString()函数提供明确的实现。

  • 不允许为copy()componentN()函数提供明确的实现。

  • 我们可以通过在构造函数中指定可见性修饰符来控制getter和setter的可见性,如下所示。

    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)

}

我们可以只设置非默认参数和我们想要的参数,使用命名参数。使用命名参数,我们可以通过显式指定参数名称后跟=来将第五个参数设置为第二个参数。这样生活就简单多了!

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())


}

//以下内容将在控制台中打印。
//书籍(名称=Android教程,作者姓名=Anupam,上次修改时间=1234567,评分=4.5,下载量=1000)
//书籍(名称=Kotlin,作者姓名=Anupam,上次修改时间=1234567,评分=5.0,下载量=1000)
//书籍(名称=Swift,作者姓名=Anupam,上次修改时间=1234567,评分=5.0,下载量=500)
//书籍(名称=Java,作者姓名=Pankaj,上次修改时间=1234567,评分=5.0,下载量=1000)
//书籍(名称=Python,作者姓名=Shubham,上次修改时间=1234567,评分=5.0,下载量=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)
}
//以下内容将在控制台中打印。
//书籍(名称=Android教程,作者姓名=Anupam,上次修改时间=1234567,评分=4.5,下载量=1000)
//书籍(名称=Kotlin,作者姓名=Anupam,上次修改时间=1234567,评分=4.5,下载量=1000)

Kotlin 数据类 equals() 和 hashCode()

hashCode() 方法返回对象的哈希码。如果两个对象相等,hashCode() 会产生相同的整数结果。因此,如果 hashCode() 相等,则 equals() 返回 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 不相等

第一个和第三个对象的哈希码相等,因此它们相等。注意equals() 方法在 Kotlin 中等同于 ==

解构声明

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
}

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

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