HashSet与TreeSet
Set是Collection的子接口,与它同级的接口还有List、Queue;
关于Set,它的显著性特征就是,无法记录数据存储的先后顺序,无法存储重复元素进入数据集合;
接下来介绍下HashSet与TreeSet
一、关于HashSet
1.hashset的存储特点?
无序性、单元性
2. HashSet是如何做到不去记录相同的元素呢?
通过了两个判断,第一个:通过HashCode;第二个:通过equals完成;
更近一步解释的:
(1)当我们创建出了一个新的HashSets,向内传入数据时,我们需要计算出HashCode值出来,计算方式我们可以自定义。
(2)将新传入的数据计算出HashCode值,之后与集合内的每个进行比较,会出现两种情况:
A:新HashCode值未出现,则直接将新值插入到集合。
B:新HashCode值出现过,则进行equals判断,将新插入元素与已存在的元素进行equals判断,这时也会出现两种结果:
C:返回ture,两个元素相同,则不会插入新值。
D:返回False,两个元素虽然HashCode值相同,但是元素本身并不相同,选择插入新元素。
import java.util.HashSet;
import java.util.Iterator;
class hashSetDemo
{
public static void main(String[] args)
{
HashSet a = new HashSet();
a.add(new Person("wangziyu01", 23));
a.add(new Person("wangziyu01", 23));// 重复
a.add(new Person("wangziyu02", 24));
a.add(new Person("wangziyu03", 25));
a.add(new Person("wangziyu04", 26));
a.add(new Person("wangziyu04", 26));// 重复 hashset重复元素进行两次判断:hashCode值判断+equals内容判断
Iterator it = a.iterator();
while (it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"..."+p.getAge());// 打印结果
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
class Person // 定义 equals比较方法 + hashCode计算方法
{
private String name;
private int age;
Person(String name, int age)
{
this.name = name;
this.age = age;
}
public boolean equals(Object obj) //定义equals比较方法
{
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
System.out.println(this.name+"..hashCode相同时,执行equals比较内容.."+p.name);
return this.name.equals(p.name) && this.age == p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public static void sop(Object obj)
{
System.out.println(obj);
}
public int hashCode() { //定义hashCode计算方法
System.out.println(this.name + "....计算hashCode");
return name.hashCode() + age * 37;
}
}
最后打印出来的结果解释:
wangziyu01…计算hashCode
wangziyu01…计算hashCode
wangziyu01…hashCode相同时,执行equals比较内容…wangziyu01 // equals比较结果相同,进行剔除
wangziyu02…计算hashCode
wangziyu03…计算hashCode
wangziyu04…计算hashCode
wangziyu04…计算hashCode
wangziyu04…hashCode相同时,执行equals比较内容…wangziyu04 // equals比较结果相同,进行剔除
最终结果:
wangziyu04…26
wangziyu01…23
wangziyu03…25
wangziyu02…24
3 HashSet总结:
(1)数据结构为哈希表,线程为非同步
(2)保证元素唯一性的原理:判断元素的hashCode值是否相同,如果相同,还会继续判断元素的equals方法,是否为true。
(3)HashCode的计算方法与equals方法可以在对象中自定义,而不需要管如何调用,它是自动的
(4) HashSet数据集无法记录存储顺序。
(5)HashSet数据集无法存储相同元素。
二、关于TreeSet:
基本介绍:TreeSet是Set下子类,TreeSet会对传入的数据进行排序。
TreeSet的底层数据为二叉树结构,使用到了compareTo方法return 0;来保证元素的唯一性。
1. TreeSet排序前需要准备哪些? 需要怎么指定排序方式?
需要让数据具有可比性:
(1)方式一:让元素自身具备比较性。
解释:元素自身实现Compareable接口(例如:学生对象的数据,让它实现可比性),之后覆盖compareTo方法,在这个方法中指定返回值,比较无非三种情况:当新加入数据比较结果较大时,返回1;当新加入数据比较结果较小时,返回-1;相同时返回0;
下面是方式一的体现结果,让Person具有可比性:
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
ts.add(new Student("lisi02",22));
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi08",19));
ts.add(new Student("lisi007",20)); // 重复元素
//ts.add(new Student("lisi01",40));
Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
class Student implements Comparable//该接口强制让学生具备比较性。
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public int compareTo(Object obj)
{
//return 0;
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;
System.out.println(this.name+"....compareto....."+s.name);
if(this.age>s.age)
return 1;
if(this.age==s.age)
{
return this.name.compareTo(s.name);
}
return 1;
/**/
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
打印结果为:
lisi02…compareto…lisi02
lisi007…compareto…lisi02 // 插入元素与集合已存在的进行比较
lisi09…compareto…lisi02
lisi09…compareto…lisi007
lisi08…compareto…lisi007
lisi08…compareto…lisi09
lisi007…compareto…lisi007 //查询到了相同的元素准备插入,
lisi02…22
lisi007…20
lisi08…19
lisi09…19
(2)方式二:让集合自身具备比较性。
解释:当元素自身不具备比较性时,或者具备的比较性不是所需要的,在集合初始化时,就有了比较方式。
具体做法:我们需要定义一个新的类,让这个类实现Comparator接口,覆盖compare方法利用compareTo比较(继续返回1,0,-1)排序,将类名传入建立好的TreeSet内,完成集合具备比较性。
// 一个例子,给指定不同长度的字符依照长短进行排序
// 问题一:当字符串的长度相同时?也需要存储
// 问题二:怎么确定主条件与副条件?
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new StringLenthComparator()); // 传入比较器
ts.add("b");
ts.add("cd");
ts.add("qwer");
ts.add("efr");
ts.add("zzzzz");
ts.add("qqqqq");
Iterator it = ts.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
}
class StringLenthComparator implements Comparator
{
public int compare(Object o1, Object o2)
{
String s1 = (String) o1;
String s2 = (String) o2;
int num = new Integer(s1.length()).compareTo(new Integer(s2.length())); //主条件
if(num==0)
return s1.compareTo(s2); // 长度相同之后的副条件
return num;
}
}
结果:
b
cd
efr
qwer
qqqqq
zzzzz // 依据副条件判断可以插入
总结HashSet与TreeSet
共同点:
- 它们都用到了迭代器比较方法
- 他们都是集合框架中的成员,有自己独有方法
- 都具有无序性与单元性
不同点:
- HashSet方法:使用的方法是,让元素先具有比较性,先比较HashCode是否一致,如果一致进行equals()比较,返回False则插入这个新的元素
- TreeSet方法:
- (1)使用接口Comparable让元素具有比较性,进行比较。
- (2)写新类继承Comparator复写compare方法(其中使用compareTo),让集合具有比较性,之后将比较器传入TreeSet中。
- HashCode底层为哈希表,TreeSet底层为二叉树(红黑树)结构