zoukankan      html  css  js  c++  java
  • java中“”==“” equals hashcode的关系

    ava中的数据类型,可分为两类:
    1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
    他们之间的比较,应用双等号(==),比较的是他们的值。
    2.复合数据类型(类)
    当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地 址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
    对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。

    public boolean equals(Object obj) { return (this == obj); }

    如果对象没有覆写equals方法默认使用Object方法,就是比较对象的内存地址是否一样。

    若某个类没有覆盖equals()方法,当它的通过equals()比较两个对象时,实际上是比较两个对象是不是同一个对象。这时,等价于通过“==”去比较这两个对象
    注意点:

    如果类没有重写equals,那么对于该类的对象来说“==”和“equals”没有区别。都是比较对象的内存地址。 但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。所以会有很多经典的面试题:

    String a = new String ("abc");
    String b = new String ("abc");
    System.out.println(a.equals(b));
    System.out.println(a==b);

    返回值是true和false

    String以及基本数据类型的包装类中都重写了hashCode()方法,他们生成的哈希码是跟他们的内容
    (这里就是指值)息息相关,也就是说在用equals()比较两个变量是否相等的时候只要他们的值相等,那么就返回true

    第二:我们可以覆写覆盖equals()方法。则通过equals()比较该类的两个对象是否相等,但是需要注意的一点如果你重写equals()方法,那么你必须重写hashCode()方法

    从开始学习Java,哈希码以及equals和==的区别就一直困扰着我。
    要想明白equals和==的区别首先应该了解什么是哈希码,因为在jdk的类库中不管是object实现的equals()方法还是String重写的equals()方法以及
    其它基本数据类型的包装类重写的euqals()方法,他们在比较对象的时候都是根据hashCode()方法返回的哈希码来判断两个对象是否相等的,所以要想搞清楚
    equals()就必须要知道什么是哈希码。
    那么究竟是什么哈希码呢?哈希码是可以根据的自己的需求,采用不同的算法产生的一个Int型数字。Object的hashCode()方法返回的哈希码是根据对
    象的内存地址来生成的,所以每个对象的哈希码是不相同的,如果你要比较的两个变量的类型没有重写Object的hashCode()方法那么这两个变量除非是指向
    相同的对象(地址相同),否则返回的一定是false。而String以及基本数据类型的包装类中都重写了hashCode()方法,他们生成的哈希码是跟他们的内容
    (这里就是指值)息息相关,也就是说在用equals()比较两个变量是否相等的时候只要他们的值相等,那么就返回true,因为他们生成的哈希码相等。有个
    值得注意的地方是:在JDK的类中只要重写的Object的equals()方法,那就肯定重写了它的hashCode()方法,因为equals()方法中在比较两个变量时,
    判断的标准就是哈希码是否一样,Object中的hashCode()方法是根据对象的内存地址生成的,如果重写了equals()方法而继续使用原来的hashCode()方
    法生成的哈希码作为判断相等的依据,那显然达不到我们要改变判断对象是否相等的标准的效果。
    既然知道了什么是哈希码,现在就可以说明equals()和==的区别了,对于没用重写Object的equals()方法的类型所生成的对象的比较,equals()
    和==是效果一样的,==比较的是两个变量所指向的对象在内存中指向的地址是否一样,而当两个变量的类型中继承了Object的equals()方法的时候,由于
    该方法比较的标准是看哈希码是否相等,而哈希码是由hashCode()方法生成的,该方法生成哈希码的依据是对象在内存中的地址,最终比较的还是地址。所
    以说equals()和==效果一样。而对于像String和那些基本数据类型的包装类来说equals()和==就不一样了,因为他们重写了Object的equals()方法和
    hashCode()方法,使得equals()方法的判断标准发生了改变,他们的判断标准是看对象的内容是否相等,这里就是指值是不是一样,因为他们的哈希码是
    根据对象的值生成的,与内存地址无关了,所以他们的equals()方法比较的是对象的值是否相等,而==比较的仍然是地址。所以equals()和==就不一样了。
    这里还要注意一下,在比较值的时候,一般==比较的是基本数据类型,而equals()比较的是引用数据类型,地址相同一定值相等,而值相等地址不一定
    相同。如果比较的是地址,那最好是用==,因为无论是否重写了Object的equals()方法,==永远比较的是地址,equals()比较的是哈希码,而哈希码生成
    的标准是由类作者自己根据需求来控制的。

    结论2:

    1、如果两个对象相同,那么它们的hashCode值一定要相同;2、如果两个对象的hashCode相同,它们并不一定相同 ,上面说的对象相同指的是用eqauls方法比较。反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等

    如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同

    1、如果两个对象相等,那么它们的hashCode()值一定相同。
    这里的相等是指,通过equals()比较两个对象时返回true。

    2.、如果两个对象hashCode()相等,它们并不一定相等。
    因为在散列表中,hashCode()相等,即两个键值对的哈希值相等。然而哈希值相等,并不一定能得出键值对相等。补充说一句:“两个不同的键值对,哈希值相等”,这就是哈希冲突。

    我们来看下面的例子

    HashSet (需要重写hashCode和equals方法)

    一般描述的事物需要往集合中添加,那么都需要重写这两个方法
    删除和判断元素是否存在,都是先判断hashCode 看看是否存在,若存在则继续equals();

    import java.util.*;
    class Person
    {
        private String name;
        private int age;
        Person(String name,int age)
        {
            this.name=name;
            this.age=age;
        }
        public int hashCode()//重写  
        {
            return name.hashCode()+age ;
        }
        public boolean equals(Object obj)//重写   Object不能换
        {
              if(!(obj instanceof Person))
                  return false;
              Person p=(Person)obj;
    
              System.out.println(this.name+"...."+p.name);
    
              return this.name.equals(p.name)&&this.age==p.age;
        }
        public String getName()
        {
            return name;
        }
        public int getAge()
        {
            return age;
        }
    }
    class HashSetDemo 
    {
        public static void main(String[] args) 
        {
            HashSet hs=new HashSet();
    
            hs.add(new Person("lisi01",30));
            hs.add(new Person("lisi02",33));
            hs.add(new Person("lisi03",35));
            hs.add(new Person("lisi02",33));
            hs.add(new Person("lisi01",30));
            hs.add(new Person("lisi04",32));
            hs.add(new Person("lisi03",35));
    
            Iterator it=hs.iterator();
    
            while(it.hasNext())
            {
               Person p=(Person)it.next();;
               sop(p.getName()+" "+p.getAge());
            }
        }
        public static void sop(Object obj)
        {
              System.out.println(obj);
    
        }
    }

    参考案例2:

    第一:
    Set集合没有顺序,也不允许重复。
    为什么要这样:模拟现实的集合。
    这里的重复只是:对象的重复
    何为对象的重复:指的就是同一个对象。
    何为同一个对象:内存中,所在的内存编号一致。
    内存编号的表示是什么:哈希码(哈希码一般是 类名 和 对象所在内存地址的十六进制数字表示 的组合)。
    第二:
    这种设置和实现中的矛盾在什么地方:
    现实生活中只要属性相同,我们就认为那是同一个对象。
    这与计算机比较同一个对象的方法不同(计算机使用内存地址,即哈希码)
    于是,就需要重写equals方法和hashCode方法(&&)来让程序的运行结果符合现实生活
    基本数据类型的实现类都已经重写了上面的两个方法。
    第三:
    为什么要重写equals方法和hashCode方法(技术实现原理):
    程序向HashSet中添加一个对象时,先用hashCode方法计算出该对象的哈希码。
    比较:
    (1),如果该对象哈希码与集合已存在对象的哈希码不一致,则该对象没有与其他对象重复,添加到集合中!
    (2),如果存在于该对象相同的哈希码,那么通过equals方法判断两个哈希码相同的对象是否为同一对象(判断的标准是:属性是否相同)
    1>,相同对象,不添加。
    2>,不同对象,添加!
    这时有两个疑问:
    1,为什么哈希码相同了还有可能是不同对象?
    2,为什么经过比较哈希码还需要借助equals方法判断?

    答:
    首先:
    按照Object类的hashCode方法,是不可能返回两个相同的哈希码的。(哈希码唯一标志了对象)
    然后:
    Object类的hashCode方法返回的哈希码具有唯一性(地址唯一性),但是这样不能让程序的运行逻辑符合现实生活。(这个逻辑就是:属性相同的对象被看作同一个对象。)

    为了让程序的运行逻辑符合现实生活,Object的子类重写了hashCode的方法(基本数据类型的实现类都已经重写了两个方法,自定义的类要软件工程 师自己重写。)

    那么:
    重写的宗旨是什么?
    重写就是为了实现这样的目的:属性相同的不同对象在调用其hashCode方法后,返回的是同样的哈希码。
    但是
    我们在重写的时候,发现几乎所有的写法都无法避免一个bug:有一些属性不同的对象(当然是不同的对象),会返回相同的哈希码。(即 重码)

    最后:
    为了解决这个问题:在哈希码相同的时候,再用equals方法比较两个对象的对应属性是否相同,这样,确保了万无一失。
    这样:上面两个问题得到解决。
    5
    下面给出一个属性不同但哈希码相同的例子:

    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    class Person {
    private String name;
    private int id;
    Person(String name,int id) {
    this.name = name;
    this.id = id;
    }
    public void setName(String name){
    this.name = name;
    }
    public String getName(){
    return name;
    }
    public void setId(int id){
    this.id = id;
    }
    public int getId(){
    return id;
    }
    public int hashCode(){
    return name.hashCode()+id; //使用字符串哈希值与Integer的哈希值的组合
                                                  //这样会产生重码,实际上重码率很高
    }
    public boolean equals(Object obj){
    if(obj instanceof Person){ //
    Person p = (Person)obj;
    return(name.equals(p.name) && id == p.id);
    }
    return super.equals(obj);
    }
    }
    public class TestHashSet2 {
    public static void main(String[] args) {
    Person p1 = new Person("a",1);
    Person p2 = new Person("b",0);
    Set<Person> set = new HashSet<Person>();
    set.add(p1);
    set.add(p2);
    Iterator<Person> it = set.iterator();
    while(it.hasNext()){
    System.out.println(it.next().getName());
    }
    }
    }
    • 总思路:hashCode不同时,则必为不同对象。hashCode相同时,根据equlas()方法判断是否为同一对象。
    • 在HashSet,HashMap,HashTable中都存在该问题。


  • 相关阅读:
    FFmpeg 协议初步学习
    HTML DOM(一):认识DOM
    ant 安装
    ubunut 查看port被哪个程序占用
    cacti气象图调整(批量位置调整、更改生成图大小等)
    内网port映射具体解释(花生壳)
    HDU 2647 Reward(图论-拓扑排序)
    白话经典算法系列之七 堆与堆排序
    Codeforces Round #191 (Div. 2)---A. Flipping Game
    Serverlet具体解释
  • 原文地址:https://www.cnblogs.com/kebibuluan/p/8350457.html
Copyright © 2011-2022 走看看