一.Set
1.泛型
- jdk1.5引入,之前都是使用Object[]
- 使用Object[]的缺点
- 获取一个值时,必须进行强制类型转换
- 调用一个方法前,必须使用instanceof判断对象类型
2.泛型的好处
- 减少了强制类型转换的次数
- 获取数据值更加方便
- 调用方法时更加安全
- 泛型只在编译时期起作用,运行阶段JVM看不见泛型类型(因为进行了类型擦除所以JVM只能看见对应的原始类型)
- 在使用时没有指定泛型类型时,默认使用Object类
- 支持lambda表达式
二.HashSet
1.特点
HashSet是无序的(无下标),并且数据不可重复,他的底层维护的是HashMap中key的部分,允许存入null元素。
2.属性
//序列化ID
static final long serialVersionUID = -5024744406713321676L;
//底层使用HashMap来保存数据
private transient HashMap<E,Object> map;
//由于Set只使用到了HashMap的key,所以此处定义一个静态的常量Object类,来充当HashMap的value
private static final Object PRESENT = new Object();
3.内部方法
(1).构造方法
//使用HashMap的默认容量大小16和默认扩容因子0.75初始化map,构造一个HashSet
public HashSet() {
map = new HashMap<>();
}
//构造一个指定Collection参数的HashSet,这里不仅仅是Set,只要实现Collection接口的容器都可以
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
//使用Collection实现的Iterator迭代器,将集合c的元素一个个加入HashSet中
addAll(c);
}
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
//使用指定的初始容量大小和扩容因子初始化map,构造一个HashSet
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
//使用指定的初始容量大小和默认的扩容因子0.75初始化map,构造一个HashSet
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
//不对外公开的一个构造方法(默认default修饰),底层构造的是LinkedHashMap,dummy只是一个标示参数,无具体意义
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
(2).add方法
//使用HashMap的add方法,将传入的值存为map的key,value使用一个静态值填充
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
(3).remove方法
//调用HashMap的remove方法实现删除
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
(4)contains方法
//调用HashMap的containsKey方法判断元素是否存在
public boolean contains(Object o) {
return map.containsKey(o);
}
三.TreeSet
1.特点
TreeSet是无序的(无下标),并且数据不可重复,但是可以排序,他的底层一般都是维护了一个TreeMap(基于构造方法)。
2.属性
/*
TreeMap实现了NavigableMap接口
存储的是一个NavigableMap。
TreeMap实现了NavigableMap。
所以TreeSet内部不一定就是使用的TreeMap。
*/
private transient NavigableMap<E,Object> m;
//静态常量Object类
private static final Object PRESENT = new Object();
3.内部方法
(1).构造方法
//通过NavigableMap直接赋值给TreeSet内部的m,此时内部使用的就是NavigableMap。
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
//新建一个TreeMap作为底层存储空间,key为泛型,因为不使用到value所以定义为一个Object类用PRESENT来填充
public TreeSet() {
this(new TreeMap<E,Object>());
}
//通过传入一个比较器构建TreeSet(用于排序)
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
//构造一个指定Collection参数的TreeSet,通过addAll将所有值传入
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
//通过传入的排序集合创建一个相同排序的集合
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
(2).add方法
//只使用Key来存储数据
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
(3).addAll方法
/*
如果TreeSet是空的,调用了addAll方法后,会直接创建一个TreeMap
*/
public boolean addAll(Collection<? extends E> c) {
// Use linear-time version if applicable
if (m.size()==0 && c.size() > 0 &&
c instanceof SortedSet &&
m instanceof TreeMap) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
TreeMap<E,Object> map = (TreeMap<E, Object>) m;
Comparator<?> cc = set.comparator();
Comparator<? super E> mc = map.comparator();
if (cc==mc || (cc != null && cc.equals(mc))) {
map.addAllForTreeSet(set, PRESENT);
return true;
}
}
return super.addAll(c);
}
(4).remove方法
//调用底层map的remove方法进行删除
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
四.LinkedHashSet
1.特点
LinkedHashSet是Set集合的一个实现,继承了HashSet,具有Set集合不重复的特点,因为采用了双向链表,所以其顺序就是插入顺序。
2.构造方法
//都是调用父类(HashSet)来构造的,HashSet的底层实际上是HashMap,所以传入一个容量为16,扩容因子为0.75
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
Comments | NOTHING