java学习——Set使用方法以及HashSet和TreeSet的区别
Set为无序集合(无序是指存入元素的先后顺序与输出元素的先后顺序不一致),不允许添加重复元素。Set是个接口,不能直接实例化对象,即Set s=new Set()是错误的。
Set的实现类常用的有:HashSet和TreeSet。
1.HashSet和TreeSet的区别:
(1)HashSet是用哈希表(散列表结构)实现的。
HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,根据该值来找到对象的存储位置。然后和该位置上所有的元素进行equals比较,如果该位置没有其他元素或者比较的结果都为false就存进去,否则就不存。即元素是按照哈希值来找存储位置,所有无序,而且可以保证无重复元素
注意:若向HashSet中存储自定义对象时,需要重写hashCode()和equals()方法(不重写的话不会报错,但运行结果和想象不一样,见下面代码)。
深入理解HashSet集合对象如何判断数据元素是否重复:
判断待存对象hashCode值是否与集合中已有元素对象hashCode值相同,如果hashCode不同则表示不重复,不用执行equals()方法; 如果相同则再调用equals方法进行检查,equals返回false表示不重复,否则表示重复。
注意:Java中的hashCode值是由对象的地址所确定的,每一个地址对应一个值。Object类中的equals方法中比较的也是对象的地址值。
(2)TreeSet是用二叉树实现的。
TreeSet可以对Set集合中的元素进行排序,TreeSet中数据是自动排好序的。
TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。
若元素自身不具备比较功能,则需要实现Comparator接口,并覆盖其compare方法。
2.Set示例代码(使用HashSet实现)
下面代码中,集合中存放的不是自定义的存储对象,所以不需要重写HashCode()和equals()。
package demo;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
public class SetTest {
public static void main(String[] args) {
Set<Date> sd;
sd=new HashSet<Date>();
System.out.println(new Date().getTime());
Date a=new Date(1565836065039L);
Date b=new Date(1565835065039L);
Date c=new Date(1565834065039L);
sd.add(a);
sd.add(b);
sd.add(c);
boolean b1=sd.add(a);
System.out.println(b1);
for(Date dt:sd) {
System.out.println(dt);
}
}
}
3.使用HashSet完成自定义类型存储
下面代码中SetStudent类为自定义存储类型,需要重写HashCode()和equals()方法。
若不重写重写HashCode()和equals()方法,不会报错,但结果和想象中不太一样。如下代码所示
(注意下面代码中,用迭代器遍历自定义类型时,取值的使用方法)
package demo;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetStudent {
public String name;
public String xuehao;
public int age;
public SetStudent(String name,String xuehao,int age) {
this.name=name;
this.xuehao=xuehao;
this.age=age;
}
public static void main(String[] args) {
Set<SetStudent> s=new HashSet();
SetStudent s1=new SetStudent("王","B15",18);
SetStudent s2=new SetStudent("李","B16",19);
SetStudent s3=new SetStudent("王","B17",18);
SetStudent s4=new SetStudent("王","B17",18);
SetStudent s5=new SetStudent("王","B15",18);
SetStudent s6=new SetStudent("张","B15",20);
s.add(s1);
s.add(s2);
s.add(s3);
s.add(s4);
s.add(s5);
s.add(s6);
Iterator it=s.iterator();
while(it.hasNext()) {
SetStudent st=(SetStudent)it.next();
System.out.println(st.name+"、"+st.xuehao+"、"+st.age);
}
}
}
运行结果为:
王、B17、18
张、B15、20
王、B15、18
王、B15、18
李、B16、19
王、B17、18
从上面的运行结果可以看出,s4,s5,s6 也存入了集合中,而实际应该是学号是唯一的,s4,s5,s6不应该被存入集合中。
重写HashCode()和equals()方法后代码示例如下:
注意:两个方法都要重写。若SetStudent不重写equals()方法,则会调用父类Objcet中的equals()方法,而Object类中的equals方法中比较的是对象的地址值。
package demo;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetStudent {
public String name;
public String xuehao;
public int age;
public SetStudent(String name,String xuehao,int age) {
this.name=name;
this.xuehao=xuehao;
this.age=age;
}
@Override
public int hashCode() {
return xuehao.hashCode();
}
@Override
public boolean equals(Object obj) {
SetStudent s=(SetStudent)obj;
return this.xuehao.equals(s.xuehao);
}
public static void main(String[] args) {
Set<SetStudent> s=new HashSet();
SetStudent s1=new SetStudent("王","B15",18);
SetStudent s2=new SetStudent("李","B16",19);
SetStudent s3=new SetStudent("王","B17",18);
SetStudent s4=new SetStudent("王","B17",18);
SetStudent s5=new SetStudent("王","B15",18);
SetStudent s6=new SetStudent("张","B15",20);
s.add(s1);
s.add(s2);
s.add(s3);
s.add(s4);
s.add(s5);
s.add(s6);
Iterator it=s.iterator();
while(it.hasNext()) {
SetStudent st=(SetStudent)it.next();
System.out.println(st.name+"、"+st.xuehao+"、"+st.age);
}
}
}
运行结果为:
王、B15、18
李、B16、19
王、B17、18
3.Set示例代码(使用TreeSet实现)
package demo;
import java.util.Set;
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
Set<Integer> s=new TreeSet();
s.add(2);
s.add(4);
s.add(3);
s.add(1);
s.add(2);
for(int i:s) {
System.out.println(i);
}
}
}
运行结果:
1
2
3
4