开发者社区> effort880829> 正文

26_ArrayList_HashSet的比较及Hashcode分析

简介: 实体类: package com.itcast.day1; public class ReflectPoint { private int x; public int y; public ReflectPoint(int x, int y) { super(); this.
+关注继续查看

实体类:

package com.itcast.day1;

public class ReflectPoint {
    private int x;
    public int y;
    
    public ReflectPoint(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ReflectPoint other = (ReflectPoint) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }
    
    
}

 

 

测试类:

package com.itcast.day1;

import java.util.Collection;
import java.util.HashSet;

public class ReflectTest2 {
    public static void main(String[] args) {
//        Collection collections = new ArrayList();
        Collection collections = new HashSet();
        ReflectPoint pt1=new ReflectPoint(3,3);
        ReflectPoint pt2=new ReflectPoint(5,5);
        ReflectPoint pt3=new ReflectPoint(3,3);
        
        //ReflectPoint类重写了hashCode方法---算法依据x,y。
        collections.add(pt1);//放入
        collections.add(pt2);//放入
        collections.add(pt3);//hashCode比较后,和pt1在同一区域;比较equals发现相同,舍弃pt3这个引用
        collections.add(pt1);//hashCode比较后,和pt1在同一区域;比较equals发现相同,舍弃
        System.out.println("修改pt2.y 前,  size= "+collections.size());//2   最终放入collections 了2个元素

        pt2.y=4;//修改参与进行hashCode运算的 y值,则pt2此时的hashCode和上面放入collections时的hashCode是不相等的。
                //这将导致Java系统无法在collections中检索到。
    
        collections.remove(pt2);//检索不到这个修改后的pt2存储区域,自然就删掉pt2失败
        System.out.println("修改pt2.y 后,  size= "+collections.size());//2 所以
        
        System.out.println("BB".hashCode()=="Aa".hashCode());//true   即:equals不相等,hashCode相等
    }
    
    /**
     * 在hash集合中,放入元素前,会先计算元素的hashCode,
     * 然后根据这个hashCode来决定存放在哪个区域。
     *
     *    如果想查找一个集合中是否包含有某个对象,大概的程序代码怎么写呢?你通常是
     *逐一去除每个元素与要查找的对象进行比较,当发现某个元素要与查找的对象进行equals
     *方法比较的结果相等时,则停止继续查找并返回肯定的信息,否则,返回否定的信息。
     *如果一个集合中有很多个元素,譬如有一万个元素,并且没有包含要查找的对象时,
     *则意味着你的程序需要从该集合中取出一万个元素进行逐一的比较才能得出结论。
     *    有人发明了一种哈希算法来提高冲击和中查找元素的效率,这种方式将集合分为若干
     *个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储
     *区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,
     *根据一个对象的哈希码就可以确定该对象应该存储的哪个区域。
     *
     *
     *    HashSet就是采用哈希算法存取对象的集合,它内部采用对某个数字N进行取余的方式
     *对哈希码进行分组和划分对象的存储区域。Object类中定义一个hashCode()方法来返回每个Java
     *对象的哈希码,当从HashSet集合中查找某个对象时,Java系统首先调用对象的hashCode()方法
     *获得该对象的哈希码,然后根据哈希码找到相应的存储区域,最后取出该存储区域内的每个元素与
     *该对象进行equals方法比较,这样不用遍历集合中的所有元素就可以得到结论。可见,HashSet集合具有很好的对象
     *检索性能,但是,HashSet集合存储对象的效率相对较低些,因为向HashSet集合中添加一个对象时,
     *要先计算出对象的哈希码和根据这个哈希码耵对象在集合中的存储位置。
     *
     *      为了保证一个类的实例对象能够在HashSet正常存储,要求这个类的两个实例对象用equals()
     *方法比较的结果相等时,他们的哈希码也必须相等。也就是说,如果obj1.equals(boj2)的结果为true,
     *那么以下表达式的结果也要为true。 obj1.hashCode()==obj2.hashCode()
     *
     *    如果一个类的hashCode方法没有遵循上述要求,那么,当这个类的两个实例对象用equals()方法
     *比较的结果相等时,它们本来应该无法被同事存储进Set集合中,但是,如果将他们存储进HashSet
     *集合中时,由于它们的hashCode()方法的返回值不同,第二个对象首先按照哈希码计算可能被放进与
     *第一个对象不同的区域中,这样,它就不可能与第一个对象进行equals方法比较了,这样可能被存储进
     *HashSet集合中了。Object类中的hashCode()方法不能满足对象被列入到HashSet中的要求,因为它的返回值
     *都是通过对象的内存地址推算出来的,同一个对象在程序运行期间的任何时候返回的哈希值都是始终不变的,所以,
     *只要是两个不同的实例对象,即使它们equals方法比较结果相等,它们默认的hashCode方法的返回值是不同的。
     *
     *上面代码ArrayList集合改为HashSet集合就可以看到这种错误的结果了,修改后的代码:
     *
     *import java.util.HashSet;
     *class Ch15_Demo5{
     *    public static void main(String[] args){
     *        HashSet users=new HashSet();
     *
     *        users.add(new User("张三",28));
     *        users.add(new User("李四",28));
     *        users.add(new User("王五",28));
     *        System.out.println(users.size());
     *
     *        users.add(new User("张三",28));
     *        System.out.println(users.size());
     *}
     *
     *}
     *
     *    只有类的实例对象要给采用哈希算法进行存储和检索时,这个类才需要按照要求覆盖hashCode方法。即使程序
     *可能暂时不会用到当前类的hashCode方法,但是为它提供一个hashCode方法也不会有什么不好,没准以后什么时候又
     *用到这个方法了,所以通常要求hashCode方法和equals方法一并被同时覆盖。
     *
     *提示:
     *    (1)通常来说,一个类的两个实例对象用equals()方法比较的结果相等时,它们的哈希码也必须相等,但反之则不成立,
     *    即equals方法比较结果不相等的对象可以有相同的哈希码,或者说哈希码相同的两个对象的equals方法比较的结果可以
     *    不等,例如,字符串"BB"和"Aa"的equals方法比较结果可以不相等,但是它们的hashCode方法返回值却相等。
     *    
     *    (2)当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后
     *    的哈希值与最初存储进HashSet集合中的哈希值就不同了,在这种情况下,即使在contains方法使用该对象当前应用作为参数去
     *    HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。
     *    
     *
     *
     *
     */
}
开始做,坚持做,重复做

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
HashSet详解
HashSet详解
41 0
ArrayList的retainAll()方法使用
retainAll()方法:list1.retainAll(list2),即list1调用retainAll()方法得到list1和list2的交集并存储在list1中,这个方法的返回值是boolean型,true代表方法执行成功。 @Test public void test1() { ArrayList arrayList1 = new ArrayList(); arrayList1.add(123); arrayList1.add.
61 0
集合之ArrayList
正则表达式有固定的规律的格式,匹配字符串 1.用于字符串格式的校验 2.按照某种字符串的格式 进行拆分 替换 3.在比较大段的字符串中寻找 符合某种格式的子字符串 有一些匹配格式的符号写法 [abc] [^abc] [a-zA-Z] [a-z[^bc]] . \d \D \s \S \w \W 有一些用来匹配出现次数 ? 0-1 *0-n +1-n {n} {n,} {n,m} Pattern p = Pattern.compile("regex"); Matche
36 0
HashMap和ArrayList的原理
面试过程中经常会被问到HashMap或者ArrayList相关的问题,简单的话就会问一些使用方面上的区别,难一点的话就会问他们之间的关系和自身的原理,今天我们就由浅入深的来分析他们之间的原理与区别。
79 0
HashMap、HashSet、TreeMap、TreeSet判断元素相同
HashMap、HashSet、TreeMap、TreeSet判断元素相同   目录 1.1     HashMap 1.2     HashSet 1.3     TreeMap 1.4     TreeSet   1.1     HashMap        先来看一下HashMap里面是怎么存放元素的。
874 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载