zoukankan      html  css  js  c++  java
  • 集合HashSet的使用

    集合中的HashSet底层是通过Hash表实现,HashSet的特点是元素唯一,但用到Hash表就跟hashCode()有了密不可分的联系,所以HashSet的唯一性是通过hashCode()方法来保证,当然光有HashCode()还不够,还有equals()也用到。从底层(HashMap的put()方法)实现代码来看,就可以清楚地看到这一点。

        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;
        }

    以上代码是HashMap的put()方法源码。那么HashSet到底是如何保证元素的唯一性,还是通过例子来说明这一点。同样,还是以HashSet存储自定义对象为例,先创建一个Person类,成员:name、age、无参、有参构造及getters和setters。

    package cn.dolphin;
    
    public class Person{
        private String name;
        private int age;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public Person(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
        public Person() {
            super();
            // TODO Auto-generated constructor stub
        }
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }    
    }

    这里先没有重写继承自Object类的hashCode()和equals()方法。

    package cn.dolphin;
    
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    public class HashSetDemo {
        public static void main(String[] args) {
            //创建集合对象
            Set<Person> set = new HashSet<>();
            //创建对象元素
            Person p1 = new Person("诸葛亮",39);
            Person p2 = new Person("赵子龙",36);
            Person p3 = new Person("关云长",38);
            Person p4 = new Person("关云长",38);
            Person p5 = new Person("关云长",38);
            //将对象元素添加到集合
            set.add(p1);
            set.add(p2);
            set.add(p3);
            set.add(p4);
            set.add(p5);
            //使用iterator()对集合遍历
            for (Iterator<Person> it = set.iterator(); it.hasNext();) {
                Person p = it.next();
                System.out.println(p);
            }
        }
    }

    运行程序的结果看到[关云长,38]出现了三次,这说明没有保证元素的唯一。现在我们在Person类中重写hashCode()和equals()。使用eclipse直接右键"Source->Generate hashCode() and equals()..."自动生成代码。

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + age;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (!(obj instanceof Person))
                return false;
            Person other = (Person) obj;
            if (age != other.age)
                return false;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            return true;
        }

    再次运行程序,看到结果中[关云长,38]只出现了一次,说明已经对相同元素进行了过滤。再回过头来看看上面的源代码,里面的if语句"if (e.hash == hash && ((k = e.key) == key || key.equals(k)))"使用的"&&",这个逻辑运算符的使用,还是有必要在这里啰嗦一下,只有"&&"的左边为true才会对右边进行判断,左边如果false,就不再看右边,这不禁使我想起一道面试题,扯远了,这个最后说。那么"&&"用在这里就意味着,如果左边的hashCode()判断false,会直接添加元素,不用再判断equals(),如果左边true,才会继续判断equals()。因为"&&"具有短路功能,这就是HashSet保证元素唯一的原理。
      下面说说刚才提到的面试题。

            int x = 1, y = 1;
            if(x++ > 3 && ++y > 3){
                ++x;
                y++;
            }
            System.out.println(x);
            System.out.println(y);        
  • 相关阅读:
    服务器常用端口
    xml处理类
    水印的代码
    Asp.net常用的51个代码(非常实用)
    poj 2453
    MOD
    LIS(最长上升子序列)
    POJ各题算法分类(转)
    poj 1496&1850
    poj 1423
  • 原文地址:https://www.cnblogs.com/magics/p/3633722.html
Copyright © 2011-2022 走看看