Collection接口之二(Set接口):
一、Set:存储无序,不可重复的集合,底层为链表
Set接口的实现类:
1、HashSet:作为set接口的主要实现类,线程不安全,可以存储null值
2、 LinkedHashSet:作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历,对于频繁的遍历操作,效率高
3、 TreeSet:可以按照添加对象的指定属性,进行排序
总结
1.Set接口中没有额外定义方法,都是使用的Collection中声明过的方法。
2.要求1:想Set中添加的数据,其所在的类一定要重写hashCode()和equals()–>一般使用快捷方式生成
要求2:重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相同的哈希值
1)对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
如果作用于引用类型的变量,则比较的是所指向的对象的地址
2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
二、Set的实现过程
Set:存储无序,不可重复的集合(HashSet)
1.无序性:不等于随机性。
存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值来决定的。
2.不可重复性:保证添加的元素按照equals()判断时,不能返回true。即:相同元素只能有一个。
3.添加元素的过程:以HashSet为例 底层:数组+链表(jdk7)
我们向HashSet中添加元素a,首先调用元素a所在类的HashCode()的方法,计算元素a的哈希值,
此哈希值接着通过某种算法计算出HashSet底层的数组存放位置(即为:索引位置),判断
数组此位置上是否有元素:
如果此位置上没有元素,则a添加成功。—>情况一
如果此位置上有其他元素b(或以链表形式存在多个元素),则比较元素a和元素b的哈希值:
如果哈希值不同,则元素a添加成功 —>情况二
如果哈希值相同,进而调用元素a所在类的equals()方法
equals()返回true,则元素a添加失败。
equals()返回false,则元素a添加成功。—>情况三
对于添加成功的情况二和情况三而言:元素a已经存在指定索引位置上的数据以链表的形式存储
jdk 7:元素a放到数组中,指向原来的元素(头部插入)
jdk 8:原来的元素在数组中,指向元素a(尾部追加)
总结:七上八下
@Test
public void test(){
Set set = new HashSet();
set.add(123);
set.add(123);
set.add(456);
set.add("AA");
set.add("AA");
set.add("BB");
set.add(new Person("Tom",22));
set.add(false);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() +"\t");
//AA BB Person{name='Tom', age=22} false 456 123
}
三、 LinkedHashSet的使用
LinkedHashSet作为HashSet的子类,在添加数据的同时,还维护了两个引用,记录前一个数据和后一个数据
优点:对于频繁的遍历操作,效率高
@Test
public void test1(){
Set set = new LinkedHashSet();
set.add(123);
set.add(123);
set.add(456);
set.add("AA");
set.add("AA");
set.add("BB");
set.add(new Person("Tom",22));
set.add(false);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() +"\t");
//123 456 AA BB Person{name='Tom', age=22} false
}
}
四、 TreeSet的使用
1.向TreeSet中添加的数据,要求是相同类的对象
2.两种排序方式:自然排序(在使用类中实现Comparable接口重写compareTo方法) 和 定制排序
3.自然排序: 比较两个对象是否相同的标准为:compareTo()返回0,不在是equals()
@Test
public void test3(){
TreeSet set = new TreeSet();
//错误
// set.add(123);
// set.add(123);
// set.add(456);
// set.add("AA");
// set.add("AA");
// set.add("BB");
// set.add(new Person("Tom",22));
// set.add(false);
//一
// set.add(133);
// set.add(456);
// set.add(-145);
// set.add(12);
// set.add(6);
//二
// //详细可见Java集合框架(一)-----Collection接口中的Person类
set.add(new Person("Tom",23));
set.add(new Person("FAS",15));
set.add(new Person("SDF",45));
set.add(new Person("WER",32));
set.add(new Person("AF",20));
//如果compareTo没有重写年龄的话,就只会有一个对象
set.add(new Person("AF",50));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() +"\t");
}
}
4.TreeSet的定制排序
比较两个对象是否相同的标准为:Comparator的compare()返回0,不在是equals()
@Test
public void test4() {
Comparator com = new Comparator() {
//按照年龄从小到大排列
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Person && o2 instanceof Person){
Person p1 = (Person)o1;
Person p2 = (Person)o2;
return Integer.compare(p1.getAge(),((Person) o2).getAge());
}else {
throw new RuntimeException("输入的类型不匹配!");
}
}
};
TreeSet set = new TreeSet(com);
set.add(new Person("Tom",23));
set.add(new Person("FAS",15));
set.add(new Person("SDF",45));
set.add(new Person("AEE",45));
set.add(new Person("WER",32));
set.add(new Person("AF",20));
//如果compareTo没有重写年龄的话,就只会有一个对象
set.add(new Person("AF",50));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
练习
public static List duplicateList(List list){
HashSet set = new HashSet();
set.addAll(list);
return new ArrayList(set);
}
@Test
public void test5(){
List list = new ArrayList();
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(2));
list.add(new Integer(3));
list.add(new Integer(3));
List list1 = duplicateList(list);
for (Object integer : list1){
System.out.println(integer);
}
}
@Test
public void test6(){
HashSet set = new HashSet();
Person p1 = new Person("AA",1001);
Person p2 = new Person("BB",1002);
set.add(p1);
set.add(p2);
p1.name = "CC";
set.remove(p1);
System.out.println(set);
set.add(new Person("CC",1001));
System.out.println(set);
set.add(new Person("AA",1001));
System.out.println(set);
}
}