我尝试在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))
}
答案 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()函数(见下文)。
答案 2 :(得分:4)
创建主要目标是保存数据的类非常普遍。如果希望您的类方便保存数据,则需要重写通用对象方法:
toString()
-字符串表示形式equals()
-对象相等hashCode()
-哈希容器注意: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 + ")";
}
}
普通班:
abstract
、open
、sealed
或 inner
,但不能用于 Data Class
答案 4 :(得分:0)
class
代表数据类型及其行为,因此从这个角度来看,data class
与class
没有什么不同。但是关于data class
的某些行为和规则使其与众不同:
toString()
将转储具有其所有成员属性的字符串。componentN
个方法,用于按get
的顺序n
个成员属性。copy
方法,该方法将成员属性作为进行差异复制的参数。这是否值得使用data class
?它与class
有什么不同吗?我不会担任评委。