继承图
分为 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的构造方法。