Java集合

继承图

分为 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方法返回false2.当使用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的构造方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值