I read about differences between class and dataclass in kotlin from this
This is the default toString() implementation of Object and Any class.If you need to print your own values you need to override toString() method in Ifoo.
class IFoo(val k:String,val h: String){
override fun toString(): String {
return "Overridden : $k - $h"
}
}
val iFoo = IFoo("Hi","Hello")
println("$iFoo")
It will provide below output for toString() . As we have overridden default implementation and provided our own implementation.
Then coming to data class.
data class Foo(val a:String)
val foo = Foo("abc","--hello")
println("$foo")
When we print data class directly it provides its own default implementation and prints all variables that are passed into the constructor.
You cannot create data class without default arguments . Data class must have atleast one argument in constructor. So it will print the value of argument. Similarly data class have its own implementation of other functions. But for normal class ,we can create object from empty constructor.
So only while inheriting data class from another data class it cant handle which toString() method to implement. So only decision made by Kotlin team not to support inheritance in data class. So data class are made as final class . So no other class can inherit it.
Here DC - Data Class , NC - Normal Class , : - Inheritance
data class Foo(val a:String,val b:String) //DC
open class IFoo(val k:String,val h: String) //NC
data class Bar(val b:Int,val c:String): Foo(b,c) // DC:DC - Not Possible
data class Bar(val b:Int,val c:String): IFoo(b,c) // Possible DC : NC - Possible
class IBar(val x:String,val y:String):Foo(x,y) // NC : DC - Not possible
class IBar(val x:String,val y:String):IFoo(x,y) // NC:NC - Possible
Hope it helps!!
CodePudding user response:
The point that you quoted means the Kotlin data classes provide some functionality out of the box which regular classes don't.
Consider this normal Kotlin class:
class Person(
val name: String,
val age: Int
)
fun main() {
val person = Person("John", 25)
println(person.toString())
}
The output for this program will be something like Person@4f023edb
. It prints the object reference. If you want a string representation of the Person
properties i.e. name
and age
, if you have to manually override the toString()
function like this:
class Person(
val name: String,
val age: Int
) {
override fun toString(): String {
return "Person(name=$name, age=$age)"
}
}
Now when you call person.toString()
it will return Person(name=John, age=25)
.
If you use a data class, this feature is provided to you by default.
data class Person( // Just add the data keyword here
val name: String,
val age: Int
)
fun main() {
val person = Person("John", 25)
println(person.toString())
}
The output of this program will be Person(name=John, age=25)
(same as above but with no extra code).
In addition to the toString()
function, a data class provides implementations for various other functions that the article mentions (like hashCode()
, copy()
, equals()
etc.). If you want to see all these, you can decompile the generated bytecode for the Kotlin data class in the above snippet. The decompiled code (in Java) looks like this:
public final class Person {
@NotNull
private final String name;
private final int age;
@NotNull
public final String getName() {
return this.name;
}
public final int getAge() {
return this.age;
}
public Person(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
}
@NotNull
public final String component1() {
return this.name;
}
public final int component2() {
return this.age;
}
@NotNull
public final Person copy(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
return new Person(name, age);
}
// $FF: synthetic method
public static Person copy$default(Person var0, String var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.name;
}
if ((var3 & 2) != 0) {
var2 = var0.age;
}
return var0.copy(var1, var2);
}
@NotNull
public String toString() {
return "Person(name=" this.name ", age=" this.age ")";
}
public int hashCode() {
String var10000 = this.name;
return (var10000 != null ? var10000.hashCode() : 0) * 31 Integer.hashCode(this.age);
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Person) {
Person var2 = (Person)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
return true;
}
}
return false;
} else {
return true;
}
}
}