Kotlin中的数据类

时间:2017-07-12 23:58:01

标签: kotlin kotlin-interop

有什么区别:

定义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种不同的方式吗?

enter image description here

4 个答案:

答案 0 :(得分:11)

equalshashCode和& toString

定义1 定义2& 2之间最重要的区别3 定义1 中的内容,equalshashcodetoString方法会被覆盖:

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

代码示例:

注意:在Kotlin中,==运算符调用对象的.equals()方法。见operator overloading on kotlinlang.org for more info

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& 2之间的另一个区别3 定义1 ,为其生成copy method。以下是如何使用它的示例:

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

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

Check out the official documentation for data classes on kotlinlang.org!

答案 1 :(得分:1)

简而言之:

  • 定义1:这是一个数据类,其主要构造函数采用两个参数nameage
  • 定义2:这只是一个类,其主要构造函数采用两个参数nameage
  • 定义3:这是一个构造函数,不带参数,并为属性""和{{1}分配默认值1name }分别

详细回答

这里要理解的是data class的概念。

数据类

创建主要目的是保存数据的类非常普遍。如果希望您的类方便保存数据,则需要覆盖通用对象方法

注意:age用于structural equality,通常用equals()实现。

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

但是,在Kotlin中,您不必概括所有这些样板代码。如果将修饰符hashCode()添加到类中,则会自动为您添加必要的方法。 dataequals()方法考虑了在主构造函数中声明的所有属性。 hashCode()的格式为toString()

此外,当您将某个类标记为数据类时,也会自动生成方法ClassName(parm1=value1, param2=value2, ...),该方法使您可以复制现有实例。当您将实例用作copy()的键或处理多线程代码时,此功能非常方便。

回到您的问题:

  • 定义1:,您无需实现通用对象方法,也可以使用HashMap方法
  • 定义2:,您将需要实现通用对象方法和copy()方法(如果需要)
  • 定义3:如果需要,您将必须实现通用对象方法和copy()方法,并且自从实现copy()方法以来没有意义。您的主要构造函数没有参数

即使不要求数据类的属性为copy(),即,您也可以像在代码中那样使用val,但强烈建议您使用只读属性,以使实例不可变。

最后,当您将一个类标记为数据类时,编译器还会生成按声明顺序与属性对应的var函数。

答案 2 :(得分: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 [no 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

答案 3 :(得分:0)

只是添加一个 Eric 接受的答案没有提到的不同之处。

数据类可以参与解构声明

如果我们有

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

}