【续Collection集合复习~~】

分析LinkedHashSet

Set<String> set = new LinkedHashSet<>(); // extends HashSet<E>,implements Set<E>

-----------之后的执行过程-------------
public LinkedHashSet() {
    super(16, .75f, true);
}
//调用了父类的构造方法
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
//调用了LinkedHashMap的构造方法
public LinkedHashMap(int initialCapacity, float loadFactor) {
    super(initialCapacity, loadFactor);
    accessOrder = false;
}
//又调用到了HashMap的构造方法
public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                           initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                           loadFactor);
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
}
//
static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
//执行完tableSizeFor以后threshold的值为16,即初始容量与threshold都为16
//其中LinkedHashSet的add方法使用的是HashSet的add方法,本质上是HashMap

结论:通过上述分析知道LinkedHashSet使用的是父类的构造方法,而HashSet的map对象是LinkedHashMap类型的,before和after来维护LinkedHasMap元素的插入顺序,所以区别就是LinkedHashSet是有顺序的,会维护数据插入的顺序。但是HashMap是无序的,LinkedHashMap实际上也是类似于双向链表的类型,LinkedHashMap用额外的链表保证插入顺序

分析TreeSet

Set<String> set = new TreeSet<>(); // extends AbstractSet<E>

-----------之后的执行过程-------------
public TreeSet() {
    this(new TreeMap<E,Object>());
}
TreeSet(NavigableMap<E,Object> m) {
    this.m = m;
}
//NavigableMap接收了一个TreeMap对象,其中m就是NavigableMap的接口对象
set.add("jack");
public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

TreeMap的put方法,用的是红黑树存储的

public V put(K key, V value) {
    Entry<K,V> t = root; // Entry<K,V> root
    if (t == null) { // 第一次添加时root为空,因此直接让root指向新节点
        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;
    if (cpr != null) {
        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();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                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;
}

由于用TreeMap的put方法时,会根据传进来的比较器来看插入的顺序如何保证,如果为空,则按照默认的比较器进行判断顺序


Map集合
  1. HashMap
  2. Hashtable
  3. LinkedHashMap
  4. TreeMap
  5. Properties

分析HashMap

Map<Integer, String> map = new HashMap<>();

public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
//余下的过程和HashSet的一样,就不展示了~~

分析Hashtable

值不能为空,Key也不能为空
注意this(11, 0.75f);初始容量为11,threshold为8,当加入第九个元素时就会对table进行扩容,扩容机制为2n+1

Map<Integer, String> map = new Hashtable<>(); // implements Map<K,V>

-----------之后的执行过程-------------
public Hashtable() {
    this(11, 0.75f);
}

public Hashtable(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal Load: "+loadFactor);

    if (initialCapacity==0) // 如果初始给的0,那么就给1
        initialCapacity = 1;
    this.loadFactor = loadFactor;
    table = new Entry<?,?>[initialCapacity];
    threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); // threshold给了8
}

map.put(1, "jack");
-----------之后的执行过程-------------
public synchronized V put(K key, V value) {
    // Make sure the value is not null
    if (value == null) {
        throw new NullPointerException();
    }

    // Makes sure the key is not already in the hashtable.
    Entry<?,?> tab[] = table;
    int hash = key.hashCode(); // 检查了key不能为空
    int index = (hash & 0x7FFFFFFF) % tab.length;
    @SuppressWarnings("unchecked")
    Entry<K,V> entry = (Entry<K,V>)tab[index];
    for(; entry != null ; entry = entry.next) {
        if ((entry.hash == hash) && entry.key.equals(key)) {
            V old = entry.value;
            entry.value = value;
            return old;
        }
    }

    addEntry(hash, key, value, index);
    return null;
}

private void addEntry(int hash, K key, V value, int index) {
    modCount++;

    Entry<?,?> tab[] = table;
    if (count >= threshold) {
        // Rehash the table if the threshold is exceeded
        rehash();

        tab = table;
        hash = key.hashCode();
        index = (hash & 0x7FFFFFFF) % tab.length;
    }

    // Creates the new entry.
    @SuppressWarnings("unchecked")
    Entry<K,V> e = (Entry<K,V>) tab[index];
    tab[index] = new Entry<>(hash, key, value, e);
    count++;
}

分析LinkedHashMap

Map<String, String> map = new LinkedHashMap<>();

-----------之后的执行过程-------------
public LinkedHashMap() {
    super(); // 调用了父类的构造方法
    accessOrder = false;
}
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

而执行LinkedHashMap的put方法时,仍旧时调用HashMap的put方法,因而没有什么不同,但是内部仍然维护了链表结构,保证是有序的(双向链表)

分析TreeMap

Map<String, String> map = new TreeMap<>();

-----------之后的执行过程-------------
public TreeMap() {
    comparator = null; // Comparator<? super K> comparator;
}
map.put("1", "jack");
-----------之后的执行过程-------------
public V put(K key, V value) {
    Entry<K,V> t = root;
    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;
    if (cpr != null) {
        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();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                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;
}

与TreeSet基本类似

Properties

Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值对的形式来保存数据。因此key和value都不能为空
Properties 还可以用于从 xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改(常用)

Map map = new Properties(); // Properties extends Hashtable<Object,Object>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值