zoukankan      html  css  js  c++  java
  • HashSet源码分析1

    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    public class SetTest {
        public static void main(String[] args) {
            Set<String> set = new HashSet<>();
            set.add("abc");
            set.add("xyz");
            set.add("abc");
    
            for (Iterator<String> it = set.iterator(); it.hasNext();) {
                System.out.println(it.next());
            }
        }
    }

    查看add方法

    /**
         * Adds the specified element to this set if it is not already present.
         * More formally, adds the specified element <tt>e</tt> to this set if
         * this set contains no element <tt>e2</tt> such that
         * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
         * If this set already contains the element, the call leaves the set
         * unchanged and returns <tt>false</tt>.
         *
         * @param e element to be added to this set
         * @return <tt>true</tt> if this set did not already contain the specified
         * element
         */
        public boolean add(E e) {
            return map.put(e, PRESENT)==null;
        }

    查看map.put方法:

     /**
         * Associates the specified value with the specified key in this map.
         * If the map previously contained a mapping for the key, the old
         * value is replaced.
         *
         * @param key key with which the specified value is to be associated
         * @param value value to be associated with the specified key
         * @return the previous value associated with <tt>key</tt>, or
         *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
         *         (A <tt>null</tt> return can also indicate that the map
         *         previously associated <tt>null</tt> with <tt>key</tt>.)
         */
        public V put(K key, V value) {
            if (table == EMPTY_TABLE) {
                inflateTable(threshold);
            }
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key);
            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;
        }

    关于set:当向Set集合中添加对象时,集合首先要计算出待添加对象的hashCode值,根据该值来得到一个位置,用于存放当前的对象。如果该位置没有对象存在,那么集合Set就会认为该对象在集合中不存在,直接添加进去。如果该位置已经有一个对象存在,接着将准备添加到集合中的对象与该位置上的对象进行equals方法比较,如果该equals方法返回false,那么集合认为该集合中不存在该对象的,再进行一次散列,将该对象放到散列后计算的地址里。如果equals方法返回true,那么集合认为该对象已经存在了,不会再将对象添加到集合中。

    在上面的例子中我们的执行结果为:

    true
    true
    false
    abc
    xyz

    第三个abc插入失败了,原因就是String类型的字符串“abc”的hashcode是相等的而且equals也是相等的(equals方法使一个字符一个字符的进行比较)。


    再看下面的例子:

    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    public class SetTest {
        public static void main(String[] args) {
        /*    Set<String> set = new HashSet<>();
            System.out.println(set.add("abc"));
            System.out.println(set.add("xyz"));
            System.out.println(set.add("abc"));
    
            for (Iterator<String> it = set.iterator(); it.hasNext();) {
                System.out.println(it.next());
            }*/
            Set<People> set2 = new HashSet<>();
            set2.add(new People("zhangsan"));
            set2.add(new People("lisi"));
            set2.add(new People("zhangsan"));
            for(Iterator<People> it = set2.iterator();it.hasNext();){
                System.out.println(it.next().getName());
            }
        }
    }
    class People{
        String name;
        public People(String name){
            this.name = name;
        }
        public String getName(){
            return this.name;
        }
    }

    运行结果为:

    lisi
    zhangsan
    zhangsan

    同样是zhangsan却能添加两次。

    如果想根据name来判断,修改代码如下:

    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    public class SetTest {
        public static void main(String[] args) {
            /*
             * Set<String> set = new HashSet<>();
             * System.out.println(set.add("abc"));
             * System.out.println(set.add("xyz"));
             * System.out.println(set.add("abc"));
             * 
             * for (Iterator<String> it = set.iterator(); it.hasNext();) {
             * System.out.println(it.next()); }
             */
            /*
             * String a = "abc"; String b = "abc"; System.out.println(a.hashCode());
             * System.out.println(b.hashCode());
             */
            Set<People> set2 = new HashSet<>();
            set2.add(new People("zhangsan"));
            set2.add(new People("lisi"));
            set2.add(new People("zhangsan"));
            for (Iterator<People> it = set2.iterator(); it.hasNext();) {
                System.out.println(it.next().getName());
            }
        }
    }
    
    class People {
        String name;
    
        public People(String name) {
            this.name = name;
        }
    
        public String getName() {
            return this.name;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj instanceof People) {
                People people = (People) obj;
                if(this.name.equals(people.getName()));
                    return true;
            }
            return false;
        }
        @Override
        public int hashCode() {
            return this.name.hashCode();
        }
    }

    执行结果为:

    lisi
    zhangsan

    当重写equals方法时,必须要重写hashCode方法。如果一个类的两个对象,使用equals方法比较时返回true,那么这两个对象必须要具有相同的hashCode。

  • 相关阅读:
    常用命令收集
    wireshark 实用过滤表达式(针对ip、协议、端口、长度和内容)
    Wireshark找不到网络接口问题
    带卡扣的网卡接口使用小Tips,大家注意插拔网线的手法啊!
    HOW TO BE SINGLE 最后那段的摘录
    github常见操作和常见错误!错误提示:fatal: remote origin already exists.
    关于工伤事故索赔计算很好用的一款APP
    MySQL文件目录格式及存放位置
    如何取消win10电脑自动更新
    推荐!手把手教你使用Git
  • 原文地址:https://www.cnblogs.com/vincent4code/p/4798175.html
Copyright © 2011-2022 走看看