kotlin中

时间:2017-05-26 04:48:26

标签: kotlin

我尝试在Kotlin Koans处解决任务#6(DataClass)。当我在代码中使用普通类时,测试用例失败了。

这是我的数据类代码:

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

fun task6(): List<Person> {
    return listOf(Person("Alice", 29), Person("Bob", 31))
}

以下是数据类的结果:

[Person(name=Alice, age=29), Person(name=Bob, age=31)]

这是我正常班级的代码:

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

fun task6(): List<Person> {
    return listOf(Person("Alice", 29), Person("Bob", 31))
}

这是正常班级的结果:

[i_introduction._6_Data_Classes.Person@4f47d241, i_introduction._6_Data_Classes.Person@4c3e4790]

这是否意味着Kotlin中普通类和数据类之间存在差异。如果是,那是什么?

更新

感谢@Mallow,你是对的。这有效:

class Person(val name: String, val age: Int) {
    override fun toString(): String {
        return "Person(name=$name, age=$age)"
    }
}

fun task6(): List<Person> {
    return listOf(Person("Alice", 29), Person("Bob", 31))
}

5 个答案:

答案 0 :(得分:14)

大多数时候我们开发人员使用类只保留类中的数据,而其他东西(比如几个默认方法和其他一些实现)也占用内存空间,这只是浪费资源。

来自官方文件:

  

我们经常创建一个类,除了保存数据之外什么都不做。在这样的类中,一些标准功能通常可以从数据中机械地导出。在Kotlin中,这称为数据类,标记为data

     

编译器自动从主构造函数中声明的所有属性派生以下成员:

     
      
  • equals()/ hashCode()对,
  •   
  • toString()形式为“User(name = John,age = 42)”,
  •   
  • componentN()函数对应于声明顺序中的属性
  •   
  • copy()函数(见下文)。   如果这些函数中的任何一个在类体中明确定义或从基类型继承,则不会生成它。
  •   

要了解详情,请查看data-classes

关于结果技术,由于toString()方法的实施,您得到的结果不同。数据类'toString()方法使用数据类属性和值来形成返回的字符串。通用类'toString()方法使用哈希代码来形成返回字符串。

答案 1 :(得分:11)

表示数据类。

  

编译器自动从所有成员派生以下成员   在主构造函数中声明的属性:

     

equals()/ hashCode()对,

     

toString()形式为“User(name = John,age = 42)”,

     

componentN()函数对应于其顺序中的属性   声明,

     

copy()函数(见下文)。

请参阅https://kotlinlang.org/docs/reference/data-classes.html

答案 2 :(得分:4)

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

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

通常,这些方法的实现非常简单,IDE可以帮助您自动生成它们。但是,在Kotlin中,您不必通用所有这些样板代码。如果将修饰符data添加到类中,则会自动为您添加必要的方法。

返回值toString()的格式为ClassName(parm1=value1, param2=value2, ...)equals()hashCode()方法考虑了在主构造函数中声明的所有属性。

copy()方法

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

即使不要求数据类的属性为val,即可以使用var,也强烈建议您使用只读属性,以便使实例是不可变的。

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

示例代码

class PersonClass(val name: String, val age: Int)
data class PersonDataClass(val name: String, val age: Int)

>>> val ron = PersonClass("Ron", 18)
>>> val harry = PersonDataClass("Harry", 17)
>>> println(ron) // notice the string representation of a regular class
PersonClass@3b6eb2ec
>>> println(harry) // notice the string representation of a data class
PersonDataClass(name=Harry, age=17)
>>> val harryClone = harry.copy() // this creates a copy of the object referenced by harry
>>> val hermione = PersonDataClass("Hermine", 16)
>>> harry == harryClone
true
>>> harry == hermione
false

总而言之,如果您需要数据的持有人,则应使用数据类,这意味着在类中添加修饰符data。这将为您生成以下方法:toString()equals()hashCode()componentN()copy(),因此避免编写样板代码。如果您使用普通班级,那么您将不会拥有所有这些“包括电池”

答案 3 :(得分:1)

Data Class 包含我们必须在类似 Java 的 Kotlin 中覆盖的内部代码生成 equals(), hashCode(), and toString()

科特林:

data class User(val name: String, val age: String)

Java:

class Student {
    public final String name;
    public final String age;

    public User(String name, String age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object other) {
        
    }

    @Override
    public long hashCode() {
      
    }

    @Override 
    public String toString() {
        return "User(name=" + name + ",age=" + age + ")";
    }
}

普通班:

  1. 可以是 abstractopensealedinner,但不能用于 Data Class
  2. 可以在没有 var 和 val 的情况下声明构造函数参数

答案 4 :(得分:0)

class代表数据类型及其行为,因此从这个角度来看,data classclass没有什么不同。但是关于data class的某些行为和规则使其与众不同:

  1. 在数据类上调用toString()将转储具有其所有成员属性的字符串。
  2. 它具有componentN个方法,用于按get的顺序n个成员属性。
  3. 它有一个copy方法,该方法将成员属性作为进行差异复制的参数。
  4. 无法打开数据类。意味着它不能有孩子(继承)。
  5. 它不能是抽象的。
  6. 它不能嵌套/内部。
  7. 它不能被密封。
  8. 尽管它可以继承,定义抽象方法和实现接口。
  9. 使用数据类对多个变量进行分组是有利的。

这是否值得使用data class?它与class有什么不同吗?我不会担任评委。