常用集合-Set
介绍常用集合Set的特点、线程安全问题、实现线程安全的方式。
### Set
#### 不安全的子类
EnumSet
、TreeSet
、HashSet
、LinkedHashSet
、NavigableSet
##### EnumSet
EnumSet
是枚举类型的容器,是一个抽象类,非线程安全,继承了AbstractSet
;
/**
* @author Josh Bloch
* @since 1.5
* @see EnumMap
* @serial exclude
*/
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable
{
/**
* Creates an empty enum set with the specified element type.
*
* @param <E> The class of the elements in the set
* @param elementType the class object of the element type for this enum
* set
* @return An empty enum set of the specified type.
* @throws NullPointerException if <tt>elementType</tt> is null
*/
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else //超过64则创建JumboEnumSet
return new JumboEnumSet<>(elementType, universe);
}
...
}
内部提供静态方法noneOf(Enum.class clazz)来创建一个实现了继承自EnumSet类的实例,如果要装载的枚举类值不超过64个,则创建的是RegularEnumSet实例,如果超过64位,则创建的是JumboEnumSet。
RegularEnumSet内部通过Bit数组来存放枚举值,而这个Bit数组其实就是一个Long类型数值,初试时是0L,添加元素时,是把对应枚举元素的ordinal(每一个枚举类的枚举值都对应一个ordinal值)值映射到64Bit上的某一个位置为1。因为Set是不能重复的,所以RegularEnumSet最多存64个元素,RegularEnumSet的add方法源码如下:
public boolean add(E e) {
typeCheck(e);
long oldElements = elements;
elements |= (1L << ((Enum<?>)e).ordinal());
return elements != oldElements;
}
JumboEnumSet内部则通过Long数组类存放枚举值,所以可以存放远远大于64个元素,当然枚举值太多也没有意义。
TreeSet
treeSet是有序集合。
/**
* @author Josh Bloch
* @see Collection
* @see Set
* @see HashSet
* @see Comparable
* @see Comparator
* @see TreeMap
* @since 1.2
*/
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable{
public TreeSet() {
this(new TreeMap<E,Object>());
}
...
}
内部通过TreeMap来存储元素,把元素存储在map的key里,通过TreeMap存储Key的有序性和无重复性来实现自己的有序性和Set的的元素无重复性;插入元素时,会根据元素的equals和compareTo方法判断大小,然后进行排序,但也只是插入的时候会进行排序,插入后修改顺序不改变。