zoukankan      html  css  js  c++  java
  • Set的非重复判断是根据什么判断的

    HashSet

    首先来看下HashSet的add()这个方法的源代码:

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
        }

    由此可知HashSet的值是存储在一个Map的key里面的,而正好Map的key是不能重复的,以下是HashSet的部分源码:

     private transient HashMap<E,Object> map;
    
        // Dummy value to associate with an Object in the backing Map
        private static final Object PRESENT = new Object();
    
        /**
         * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
         * default initial capacity (16) and load factor (0.75).
         */
        public HashSet() {
        map = new HashMap<E,Object>();
        }
    
     public Iterator<E> iterator() {
        return map.keySet().iterator();
        }
    
    public int size() {
        return map.size();
        }

    接着再看看HashMap里的put()方法是如何判断值是否重复的,以下是HashMap的put()源码:

    public V put(K key, V value) {
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key.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))) {
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }
    
            modCount++;
            addEntry(hash, key, value, i);
            return null;
        }

    关键这句:if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

    它先进行了hashCode的判断,如果hashCode相等再接着使用==来判断传入的对象的引用地址是否相等及使用传入对象的equals()方法来进行判断。

    接着再看看HashSet的contains()方法的源码:

    public boolean contains(Object o) {
        return map.containsKey(o);
        }

    调用的是Map的containsKey()方法,以下是HashMap的containsKey()源码:

    public boolean containsKey(Object key) {
            return getEntry(key) != null;
        }
    
    final Entry<K,V> getEntry(Object key) {
            int hash = (key == null) ? 0 : hash(key.hashCode());
            for (Entry<K,V> e = table[indexFor(hash, table.length)];
                 e != null;
                 e = e.next) {
                Object k;
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            }
            return null;
        }
    if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k)))) 和put()方法的判断是一样的。


    TreeSet
    看看TreeSet的add()方法的源码:
    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
        }
    
    

    它也同样是由一个Map的key来进行存储,看看这个Map:

    /**
         * The backing map.
         */
        private transient NavigableMap<E,Object> m;

    接着看看TreeSet的构造函数:

    TreeSet(NavigableMap<E,Object> m) {
            this.m = m;
        }
    
    public TreeSet() {
        this(new TreeMap<E,Object>());
        }

    TreeSet的无參构造函数里实例化了一个TreeMap对象,下面看看这个TreeMap对象:

    public class TreeMap<K,V>
        extends AbstractMap<K,V>
        implements NavigableMap<K,V>, Cloneable, java.io.Serializable
    {
    
     private final Comparator<? super K> comparator;
    
     public TreeMap() {
            comparator = null;
        }
    
    public TreeMap(Comparator<? super K> comparator) {
            this.comparator = comparator;
        }
    //其他略...
    }
    public interface NavigableMap<K,V> extends SortedMap<K,V>

    接着看这个TreeMap的put()方法:

    public V put(K key, V value) {
            Entry<K,V> t = root;
            if (t == null) {
            // TBD:
            // 5045147: (coll) Adding null to an empty TreeSet should
            // throw NullPointerException
            //
            // compare(key, key); // type check
                root = new Entry<K,V>(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();
                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<K,V>(key, value, parent);
            if (cmp < 0)
                parent.left = e;
            else
                parent.right = e;
            fixAfterInsertion(e);
            size++;
            modCount++;
            return null;
        }

    TreeMap存储的对象是会进行排序的,所以存储的对象都必须实现Comparable接口。

    TreeMap先判断Comparator对象是否为空,不为空则使用当前的Comparator对象的compare方法来进行比较排序,若发现compareTo返回的值为0,则认为这两个对象是重复的了,然后覆盖原来的value;如果Comparator对象为空,则使用集合对象实现的Comparable接口的compareTo方法来进行比较排序,同样地当返回值是0时就认为对象重复,然后覆盖原来的value。

     
  • 相关阅读:
    使用WCF建立起Silverlight客户端与服务端的桥梁
    Silverlight WCF RIA服务(三十三)身份验证、角色、个性化 4
    陶哲轩实分析习题 12.1.3
    Asymptote 学习记录(6) 练习用模块roundedpath画出一个图
    使用Asymptote的循环功能画出绿叶阵
    使用Asymptote的循环功能画出绿叶阵
    度量空间的一个例子:离散度量空间
    练习: 使用Asymptote 画出字母R的轮廓曲线
    练习: 使用Asymptote 画出字母R的轮廓曲线
    陶哲轩实分析命题 11.10.7
  • 原文地址:https://www.cnblogs.com/liuxin-listenx/p/3163445.html
Copyright © 2011-2022 走看看