package com.sf.jinjian.collection;
import com.sf.jinjian.data.Employee;
import org.junit.Test;
import java.util.*;
public class SetTest {
@Test
public void test01(){
Set set = new HashSet();
set.add(123);
set.add(456);
set.add(new Employee(1,"gy"));
System.out.println(set);
}
@Test
public void test02(){
Set set = new linkedHashSet();
set.add(123);
set.add(456);
set.add(new Employee(1,"gy"));
System.out.println(set);
}
@Test
public void test03(){
Set set = new TreeSet();
set.add(new Employee(1,"gy"));
set.add(new Employee(2,"ab"));
set.add(new Employee(3,"er"));
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
//定制排序
@Test
public void test04(){
Comparator com = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Employee && o2 instanceof Employee){
Employee emp1 = (Employee) o1;
Employee emp2 = (Employee) o2;
return Integer.compare(emp1.getAge(),emp2.getAge());
}else {
throw new RuntimeException("输入的数据格式不对");
}
}
};
// TreeSet(com)这里加了com就是按照定制排序了即按照年龄来排序,如果没有加就是按照自然排序和上面一样
Set set = new TreeSet(com);
set.add(new Employee(1,"gy",2,200));
set.add(new Employee(2,"ab",3,300));
set.add(new Employee(3,"er",4,400));
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
Set接口存储的是无序的不可重复的元素,主要实现类有
HashSet:作为Set接口的主要实现类,线程不安全,可以存储null值 。
linkedHashSet:作为HashSet的子类,在遍历其内部数据时,可以按照元素添加的顺序遍历。
TreeSet:可以按照添加对象的指定属性进行排序 。
2、set接口的无序性和不可重复性,以HashSet为例
无序性:指的是再往HashSet里面添加元素时,不是按照底层数组的索引位置添加的,而是根据hashCode值计算出的在数组里面的位置的。
不可重复性:保证往Set里面添加的元素按照equals()判断时,不能返回true。即相同的元素只能返回一个。
3、hashSet添加元素的过程
我们向hashSet里面添加元素a,首先根据元素a所在类的hashCode方法,计算元素a的hash值。
此通过对hash值 * 进行某种算法计算出该元素在hashSet底层数组里面对应的位置(索引位置)。判断此位置上面是否有元素 *
如果没有元素,则直接将元素a添加到该位置 -----------》情况1
如果有(可能以链表的形式存储了多个元素),则计算元素a与该位置上面各个元素的hash值。 如果hash值都不相同,则直接将元素a添加到该位置,如果有链表则按照相应规则添加到链表里面 。(情况2 )
如果hash值有相同的,则调用元素a的equals方法与hash值相同的元素进行对比
如果结果为false则直接添加元素a到相应的位置-------》(情况3 )
如果结果为true则表明该元素与某个元素相同,则不需要添加即可。
* 对于情况3和情况2,元素a与已经存在索引对应位置上面的元素用链表存储 。
jdk7:元素a放在数组中,指向原来的元素 *
jdk8:原来的元素在数组中,指向元素a * *
4、注意:向Set里面添加的数据,其所在的类的hashCode()方法和equals()方法一定要重写,要做到 * 相同的对象具有相同的hash值。重写的小技巧:对象中用作equals的属性也要在hashcode方法里面使用到。
5、linkedHashSet:它的底层还是hashSet,只不过是在每个元素里面又多存储了指向前一个和后一个元素的信息,这样 * 遍历数据就会笔单纯的hashSet效率高。它依旧是无序的,只不过遍历的顺序可以按照添加该元素的顺序。无序指的是 * 在添加该元素时不是按照线性的数组索引存储的。
6、TreeSet: *
(1)往TreeSet里面添加元素,必须是同一个类的对象才行 *
(2)TreeSet里面添加元素,这个元素所属的类必须实现排序方法(自然排序(Comparable接口实现)和定制排序) *
(3)在自然排序里面,比较两个元素是否相同是看该类的compareTo返回是否为“0”,而不再是看equals()方法了
(4)在定制排序里面,比较两个元素是否相同是看该类的compare()返回是否为“0”,而不再是看equals()方法了



