继承图
分为 Collection 和 Map 两大类,其下又有很多子类,如下所示(很多接口、类未列出):
=======================================================================================================================
(I)Iterable
|
(I)Collection ----------------------------------------(I)Collection
/ \ /
(I)List (I)Set (I) Queue
\ / \ /
ArrayList、LinkedList、Vector (I)SortedSet HashSet (I) BlockingQueue、(I) AbstractQueue、(I) Dequeue
\ / \ . . .
Stack (I)NavigableSet LinkedHashSet . . .
\ . . .
TreeSet
=======================================================================================================================
(I)Map
/ | \
(I)SortedMap | HashMap、Hashtable
/ | \
(I)NavigableMap | LinkedHashMap
\ |
TreeMap /
(I)ConcurrentMap
\
ConcurrentHashMap
=======================================================================================================================
Set
1.Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。
2.当使用Hashset时,hashCode方法就会得到调用,判断已经存储在集合中的对象的hashcode值是否与增加的对象的hashcode值一致;
如果不一致,直接加进去;
如果一致,再进行equals方法的比较,equals方法如果返回true表示对象已经加入了,就不会增加新的对象,否则加进去。
--在set中,重复元素是指:hashCode值相同且equals为true的两个对象。
==============================================================
HashSet的源码(HashSet的底层是HashMap实现)
public HashSet() {
map = new HashMap<E,Object>();
}
//当时有add的方法将对象加到Set中时,实际上是将该对象为底层所维护的map对象的key,而value则是同一个对象(该对象没有起什么作用)
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode()); //调用hashCode方法
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //调用equals方法
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
treeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态:
排序状态
/ \
定制排序 自然排序(默认)
TreeSet判断两个对象不相等的方式是元素的CompareTo方法或Comparator的compare方法的返回值是大于0还是小于0。
TreeSet的源码(TreeSet的底层是TreeMap实现)
public TreeSet() {
this(new TreeMap<E,Object>());
}
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
TreeSet或TreeMap大部分情况下不可以存key==null的元素,特殊情况下可以,比如:
//初始化时传入一个Comparator,且重写的compare方法中不会报空指针异常
new TreeMap<String,String>( new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 1;
}
} ).put(null,null);
new TreeSet<String>( new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 1;
}
} ).add(null);
public V put(K key, V value) {
Entry<K,V> t = root; // 先造根,TreeSet集合底层数据结构是红黑树(是一个自平衡的二叉树)
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator; // 因为用的是TreeSet的无参构造方法,是自然排序,没有用到comparator比较器
if (cpr != null) { // 所以此时的comparator = null,则程序执行else里面的代码
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
} else {
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key; // 此接口Comparable强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。。
do { // 举例中我们使用的是包装类Intrger,而Integer类实现了Comparable接口。此例子是向上转型。
parent = t;
cmp = k.compareTo(t.key); // 类的 compareTo 方法被称为它的自然比较方法。
if (cmp < 0) // int compareTo(T o) 比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
LinkedHashSet(集双向链表顺序性和hash表的高效性及Set的元素不重复性于一体):
顺序性的HashSet
/ \
插入顺序(默认) 访问顺序(初始化时需设置accessOrder为true)
同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。
这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。
public LinkedHashMap() {
super();//调用HashMap的构造方法,其实就是初始化Entry[] table
accessOrder = false;
}
这里accessOrder设置为false,表示不是访问顺序而是插入顺序存储的,是默认值,
表示LinkedHashMap中存储的顺序是按照调用put方法插入的顺序进行排序的。LinkedHashMap也提供了可以设置accessOrder的构造方法。