Kotlin系列之通用对象方法

今天我们来说说Kotlin中的通用对象方法。

什么是通用对象方法呢?其实就是所有对象都拥有的方法,再进一步说,就是toString()equals()hashCode()。今天就来看看Kotlin中的这几个方法。

老规矩,先来稍微提一下在Java中这三个方法的一些知识点,再对比着来看。

Java中的通用对象方法

在Java中,这几个方法都是Object的方法。
toString()是用来表示一个对象的字符串表示,它的出现大部分时候是为了将对象的属性以字符串形式表示打印出来。如果我们没有重写一个对象的toString()方法,那么它默认是类名@53ffe12a这样的形式。我们可以通过重写对象的该方法来使打印结果更直观更好理解。

equals()方法是为了判断两个对象是否相等。默认情况下,它的作用和==的作用是一样的,都是比较两个对象的引用(地址),我们可以通过重写该方法用于比较两个对象的属性是否相等。

hashCode()方法最终是计算出一个对象的哈希值。

这里需要注意的是,在Java中有这样的契约:如果两个对象使用equals()方法比较相等,那么它们的hashCode()值也必须相等,但如果两个对象的hashCode()值相等,这两个对象不一点相等。

下面通过代码来简单看一下:

Java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class User {

private String name;
private int age;

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

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;

User user = (User) o;

if (age != user.age)
return false;
return name != null ? name.equals(user.name) : user.name == null;
}

@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}

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

public static void main(String[] args) {
User user2 = new User("雨", 21);
User user1 = new User("晴", 21);

System.out.println(user1);
System.out.println(user1.equals(user2));

System.out.println(user1.hashCode());
System.out.println(user2.hashCode());
}
}

运行结果

1
2
3
4
User{name='晴', age=21}
false
813089
1197613

上面的代码重写了这几个方法,只是作为简单复习一下,那我们下面看看上面的代码用Kotlin该怎么写呢?

Kotlin中的通用对象方法

在Kotlin中也是一样,我们也需要重写toString()方法。如下面这样。

Kotlin代码

1
2
3
4
5
6
7
8
open class User(val name: String, val age: Int){
override fun toString() = "User{name='$name', age=$age}"
}

fun main(atgs: Array<String>){
val user1 = User("遇", 21);
println(user1)
}

上面的代码重写了toString()方法,打印的结果和java是一样的。注意的是override关键字是强制的。同时上面还用到了$变量名这样的形式在字符串中直接引用变量,Kotlin会自动帮我们替换为对应的变量值,这在Kotlin中被成为模板字符串。

下面我们再来看看equals()方法和hashCode()方法的重写。与Java中一样的契约,equals()方法和hashCode()方法必须保持同步重写。

Kotlin代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
open class User(val name: String, private val age: Int){
override fun toString() = "User{name='$name', age=$age}"

override fun equals(other: Any?): Boolean {
if (other == this){
return true;
}
if (other == null || other !is User){
return false;
}
return name == other.name && age == other.age
}

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

上面的代码重写了equals()hashCode()方法。

有人可能会有疑问,这里补充一下,Any相当于Java中的Object,但是下面在取name属性时并没有强制类型转化other的类型到User,这就是Kotlin中的重大特性之一智能转换

有一点要注意,在Kotlin中==用来比较两个基本类型的值和两个对象,相当于Java中的equals(),它会在背后调用equals()方法,如果想比较两个对象的属性可以使用===
这里再补充一下为什么需要保持equals()hashCode()的一致性。我们都知道Set这种数据结构是保证其中的元素都是唯一的,只有一个,在HashSet这种集合中,做了优化,会先比较两个对象的哈希值,如果哈希值相等再比较两个对象的值,如果哈希值不想等则认为是两个相同的元素。如果我们不能保证对象的equals()hashCode()的一致性,那么在使用这种集合时就会出错。

写在最后

通过上面的对比主要还是要注意==在Java和Kotlin中是不一样的,同时还发现同样的功能,Kotlink可以用更简洁的代码去实现,下面一节我们将会学到更简洁的代码。

如果博客对您有帮助,不妨请我喝杯咖啡...