Set: 元素顺序无序,唯一。
HashSet 元素无序,并不保证顺序永恒不变,因为是根据对象的哈希值进行排序,相对底层哈希值可能是有顺序可以找,但是对于我们来说元素的哈希值是不固定的也是未知的,所以导致集合内元素是无序存储。
TreeSet
可以对元素进行排序,并且保证集合内元素唯一。可以排序是因为底层结构是二叉树,二叉树可以根据树节点进行存储和取出。
----------------------------------------------------------------------------------------------
HashSet: HashSet底层是哈希表,因为无序,所以我们对HashSet需要掌握的就是去重元素。
----------------------------------------------------------------------------------------------
HashSet去重元素:
这里只总结需要自定义规则去重元素。一般是针对引用类型对象
eg:学生对象(姓名年龄相同即为同一元素)
------------------------------------
为什么要自定义规则?
因为学生对象在每次创建的时候都会生成新对象,这些对象在内存里的哈希值肯定不会相同,所以java提供给我们的比较哈希值得方法就不能满足我们的需求,因此我们要根据自己的规则来定义哪些元素是相同元素。
------------------------------------
怎么实现?
因为哈希表比较相同元素依赖的是hashCode()方法和equals()方法,因此我们只需要重写这两个方法即可。
hashCode底层代码如下(仅判断部分):
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
通过代码可以看出底层的比较是先比较哈希值,再比较equals,如果前面就已经相同,就不会调用equals方法,所以我们依次是先重写hashCode()和equals()。
------------------------------------
怎么重写?
先判断hashCode是否相同
相同----继续走equals方法,根据返回值决定元素是否重复。(true:重复,不添加到集合;false 不重复,添加元素到集合)
不同----直接添加到集合
重写方法:
【重写 hashCode()】:
把对象所有的变量值相加即可。基本类型加值,引用类型加它的hashCode值。
代码实现:
public int hashCode(){
return this.name.hashCode()*13 + this.age*12;//后面乘以一个数是为了防止出现对应的值分别是1、2 -----2、1 这类情况导致的误判hashCode值相同。
}
【重写equals()】:
三步:1、判断是不是同一个对象,如果是,直接返回true
2、判断是不是对应的类型(这里是判断是不是Student类型)
3、接收的参数强转成对应类型,然后添加比较规则。
代码实现:
public boolean equals (Object obj){
//1、判断是不是同一个对象
if(this == obj){
return true;
}
// 2、判断是不是对应的类型
if(!(obj instanceof Student)){ //如果obj不是Student类型
return false;
//这步在调用集合的add();方法时候其实并没有什么意义,这步主要是为了防止其他方法调用equals的时候程序出问题做的优化,例如System.out.prinln(new Student("隔壁老王").equals(new Animal("拉拉")));
}
Student s = (Student)obj;//把接收进来的对象转成Student类型就可以调用它的参数了。
return this.name.equals(s.name) && this.age == s.age;//判断姓名和年龄都相同就为相同元素。
}
------------------------------------
上面扯这么多,其实如果不明白,那最起码要明白在什么情况下需要重写hashCode()和equals()方法,然后用eclipse的soure里面自动生成就可以了,这是最次要求了。
----------------------------------------------------------------------------------------------
TreeSet TreeSet的底层是二叉树,所以它和HashSet的区别就是在保证元素唯一的时候还可以进行简单的排序。
排序方式有两种,
1、自然排序(使元素具有比较性):
这个调用的是TreeSet的无参构造,但是实体类需要
A、继承Comparable<E>接口
B、重写conpareTo(Object o);方法
代码实现:
public class Student implements Comparable<Student>{
@Override
public int compareTo(Student s) {
int num1 = this.getAge() - s.getAge() ;//s放前面是从大到小排,s放后面是从小到大排
int num2 = (num1 == 0) ? this.getName().compareTo(s.getName()) : num1;
return num2;
}
}
2、比较器排序(使集合具有比较性,这也是两个比较器的不同之处):
这里使用的是TreeSet的带参构造,里面传了一个Comparator接口的对象
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num1 = this.getAge() - s.getAge() ;//s放前面是从大到小排,s放后面是从小到大排
int num2 = (num1 == 0) ? this.getName().compareTo(s.getName()) : num1;
return num2;
}
});
|
|