11

有什么区别:

定义 1

data class Person (var name:String, var age:Int)

定义 2

class Person (var name:String, var age:Int)

定义 3

class Person (){
    var name:String = ""
    var age:Int = 1
}

在我使用自动完成功能的 3 种情况下,我看到了与 POJO 相同的可用方法……这是否相同,但有 3 种不同的方式?

在此处输入图像描述

4

4 回答 4

20

equals, hashCode, &的差异toString

定义 1定义 2 & 3之间最重要的区别是,在定义 1equalshashcodetoString方法为您被覆盖:

  • equalshashCode方法测试结构平等
  • toString方法返回一个漂亮的、人性化的字符串

代码示例:

注意:在 Kotlin 中,==运算符调用对象的.equals()方法。有关更多信息,请参阅kotlinlang.org 上的运算符重载

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

@Test fun test1()
{
    val alice1 = Person1("Alice", 22)
    val alice2 = Person1("Alice", 22)
    val bob = Person1("bob", 23)

    // alice1 and alice2 are structurally equal, so this returns true.
    println(alice1 == alice2)   // true

    // alice1 and bob are NOT structurally equal, so this returns false.
    println(alice1 == bob)      // false

    // the toString method for data classes are generated for you.
    println(alice1)     // Person1(name=Alice, age=22)
}

@Test fun test2()
{
    val alice1 = Person2("Alice", 22)
    val alice2 = Person2("Alice", 22)
    val bob = Person2("bob", 23)

    // even though alice1 and alice2 are structurally equal, this returns false.
    println(alice1 == alice2) // false
    println(alice1 == bob)    // false

    // the toString method for normal classes are NOT generated for you.
    println(alice1)  // Person2@1ed6993a
}

构造函数的区别

定义 1 和 2定义 3之间的另一个区别是:

  • 定义 1 和 2都有一个带有 2 个参数的构造函数
  • 定义 3只有一个无参数构造函数,它为类成员分配默认值。

代码示例:

data class Person1 (var name:String, var age:Int)
class Person2 (var name:String, var age:Int)
class Person3 ()
{
    var name:String = ""
    var age:Int = 1
}

@Test fun test3()
{
    Person1("alice",22)     // OK
    Person2("bob",23)       // OK
    Person3("charlie",22)   // error

    Person1()   // error
    Person2()   // error
    Person3()   // OK
}

copy方法_

最后,定义 1定义 2 & 3之间的另一个区别是,在定义 1中,为它生成了一个copy方法。这是如何使用它的示例:

val jack = Person1("Jack", 1)
val olderJack = jack.copy(age = 2)

// jack.age = 1
// olderJack.age = 2

查看 kotlinlang.org 上数据类的官方文档!

于 2017-07-13T00:16:12.297 回答
1

简而言之:

  • 定义1:这是一个数据类,主构造函数有两个参数nameage
  • 定义2:这只是一个主构造函数带有两个参数的类,name并且age
  • 定义 3:这是一个类,其构造函数没有参数,并分别为属性分配默认值""1nameage

详细解答

这里重要的是要理解数据类的概念。

数据类

创建主要目的是保存数据的类是很常见的。如果您希望您的类成为您的数据的方便持有者,您需要覆盖通用对象方法

注意:equals()用于结构相等,通常用hashCode().

通常,这些方法的实现很简单,您的 IDE 可以帮助您自动生成它们。

但是,在 Kotlin 中,您不必通用所有这些样板代码。如果将修饰符添加data到类中,则会自动为您添加必要的方法。equals()andhashCode()方法考虑了主构造函数中声明的所有属性。toString()将具有以下格式ClassName(parm1=value1, param2=value2, ...)

此外,当您将一个类标记为数据类时,该方法copy()也会自动生成,允许您复制现有实例。当您将实例用作 a 的键HashMap或处理多线程代码时,此功能非常方便。

回到你的问题:

  • 定义 1:您不需要实现通用对象方法,并且您还可以copy()使用该方法
  • 定义 2:如果需要,您将必须实现通用对象方法和copy()方法
  • 定义3:如果需要,您将必须实现通用对象方法和copy()方法,并且实现该方法没有意义,copy()因为您的主构造函数没有参数

即使数据类的属性不需要是val,即您可以var在代码中使用,但强烈建议您使用只读属性,以便使实例不可变。

最后,当您将类标记为数据类componentN()时,编译器也会生成与声明顺序中的属性相对应的函数。

于 2020-09-24T13:06:08.393 回答
0

只是为了增加一个埃里克接受的答案没有提到的区别。

数据类可以参与解构声明

所以如果我们有

class Person(val name: String, val age: Int) 

data class Person2(val name: String, val age: Int)

接着

fun main() {
    
    val person = Person("Kal", 34);  //normal class instance
    val person2 = Person2("Kal", 34);  //data class instance

    val (name, age) = person; //This does not compile and shows error
    //Destructuring declaration initializer of type Employee must have a 'component1()' function
    //Destructuring declaration initializer of type Employee must have a 'component2()' function

    val (name2, age2) = person2; //no problem here

}
于 2021-02-26T10:59:57.637 回答
0

定义 1 ( data class Person(var name: String, var age: Int) 等价于

/* every class by default in kotlin is final but a data class CAN'T be open */
final class Person(var name: String, var age: Int) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other?.javaClass != javaClass) return false

        other as Person

        if (name != other.name) return false
        if (age != other.age) return false

        return true
    }

    override fun hashCode(): Int {
        var result = name.hashCode()
        result = 31 * result + age
        return result
    }
}

val person = Person("Name", 123)

定义 2(class Person(var name: String, var age: Int[无data修饰符])等价于

class Person(var name: String, var age: Int) {
}

val person = Person("Name", 123)

定义 3 等价于

class Person() {
    var name: String = ""
    var age: Int = 1
}

val person = Person() // name = "", age = 1 (by default)
person.name = "Name"
person.age = 123
于 2017-07-13T00:30:50.650 回答