标签:cli string 自定义对象 经验 out 很多 [] 去掉 als
HashSet存储过程中如何排除不同的自定义对象?
先看一个小demo
public class Demo1 {
public static void main(String[] args) {
//Person4类是一个失血模型,它有姓名和年龄两个属性
HashSet<Person4> set = new HashSet<>();
set.add(new Person4("张三", 23));
set.add(new Person4("张三", 23));
set.add(new Person4("李四", 24));
set.add(new Person4("李四", 24));
set.add(new Person4("李四", 24));
/*
* 直接打印,我们会发现,它把5个元素加入进去了,包括我们认为“重复”的元素
* 可是,HashSet不是号称不可重复吗?这是为什么?
*/
System.out.println(set);
}
}
HashSet在存储自定义的对象比如Person4(含name和age属性)时,如果存放name和age值相同的对象时,它都会存放进去。因为我们把它当作是相同的元素是根据它的属性值判断,而程序会为每个new出来的对象计算出不同的hashcode码,所以它认为是不同的对象,都会存放进去。
如何让它有效排除我们认为的“所有属性值相同的对象就是同一个对象”在这种定义下的同一种对象呢?
首先我们要去了解它的底层实现,即:
它判断是否相同的时候,肯定用了equals方法,他在计算hashcode的时候,应该用到了hashCode方法,那么它的执行流程和内部是怎么实现的呢?
我们追溯HashSet的源码,首先我们用到了add方法,它在add的时候肯定会进行是否存在相同对象的判断。我按住ctrl+鼠标左键点进去,一层一层追溯,结果懵逼了,发现里面涉及了很多以我目前实力看不懂的代码,怎么办?
先不管三七二十一,因为根据之前看源码的经验,我发现如果一个方法的底层如果用了equals方法,那么它调用的是obj的equals方法。什么意思呢?就是说它其实调用的是被操作对象的方法,我们每一个Person4对象的equals方法,这样实现的目的应该是为了我们使用者可以方便地重写equals方法底层实现从而实现我们自己的个性化使用。
我直接在person4里重写了equals方法如下:
@Override
public boolean equals(Object obj) {
//先把obj强制转换成person4对象
Person4 p = (Person4) obj;
//改成根据各属性的值判断是否同一个对象
return p.name.equals(this.name) && p.age == p.age;
}
再运行了下程序,发现并不起作用,重复元素还是存在。
我再一咬牙,再把hashCode方法一并改写了:
@Override
public int hashCode() {
return 10;
}
我让hashCode方法都返回10,发现重复元素都没了。
到了这里,不禁困惑,为什么这样就可以了呢?
后来,经过查阅资料,观看视频得知,hashSet底层的add方法大概流程是这样的:先比较hashcode码,不相同则插入成功,如果相同,则用equals比较。
再反观我们上面的程序,因为我让它hashcode都变成了10,所以他们最终都是通过equals比较的,equals被我重写,它就能够去掉重复的元素。
但是,实际开发中这样效率是不高的,我们应该让它尽可能少调用方法,达到效率的提升,特别是操作的元素数量特别多的时候。
所以,我们就应该让它在第一关:hashcode码判断的时候,就应该让不同的元素尽量返回不同的hashcode码,一次判断就结束。
如果你使用的是eclipse,那么可以利用它自带的便捷功能:自动重写equals和hashcode方法,并且实现了我们上面提的要求(它为我们考虑好了算法)。按住shift+alt+s,点击generate hashCode( ) and equals( ),他会自动重写我们的两个方法。你想学习它的算法怎么实现的,可以看它生成的代码。
标签:cli string 自定义对象 经验 out 很多 [] 去掉 als
原文地址:https://www.cnblogs.com/iisme/p/10480246.html