Java中==和equals的区别,equals和hashCode的区别

Java中==和equals的区别

1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
他们之间的比较,没有hashcode和equals方法,基本变量的比较方式就只有==,比较的是他们的值。

2.如果是你自己定义的一个类,比较自定义类用equals和==是一样的,都是比较内存地址,因为自定义的类是继承于object,而object中的equals就是用==来实现的。

3.(1)对于String类型或者是包装类如Integer,equals比较的就是堆中的值即比较实际内容,是因为String等常用类已经重写了object中的equals方法,让equals来比较实际内容。
(2)对于String类型或者是包装类如Integer时,用String=“”;这种形式进行赋值时,值相同,则==返回true。但是用new String(),赋值相同,但是==返回false。说明String=“”时,java会检查在堆中是否由相同的值,如果有,把新对象的地址也同老对象的地址赋为相同,因此==比较会相同。但是new String()开辟的就是两个栈,因此用==比较不会相同。对于包装类,如Integer=“”;时,在-128-127会有缓存,请看下面程序。其他的情况与String类似。代码如下:

public class Test {

     public static void main(String[] args) {

        String s1 = "abc";
        String s2 = "abc";
        System.out.print("String类型是s1==s2:");//比较内容
        System.out.println(s1 == s2);//true


        String s3 = new String("abc");
        String s4 = new String("abc");//
        System.out.print("String类型用new String()是s1==s2:");//比较地址
        System.out.println(s3 == s4);//false
        System.out.println(s1 == s3);//false


        Integer i1 = 1;
        Integer i2 = 1;
        System.out.print("包装类型是i1==i2:");
        System.out.println(i1 == i2);//true


        Integer i3 = 128;
        Integer i4 = 128;//此时输出false是因为Integer在-128-127之间会缓存,超出这个范围就不会缓存了
        System.out.print("包装类型是i3==i4:");
        System.out.println(i3 == i4);//false


        Integer i5 = new Integer("1");
        Integer i6 = new Integer("1");
        System.out.print("包装类型用new Integer()是i5==i6:");//同String,比较地址
        System.out.println(i5 == i6);//false(用new Integer()多少都不会缓存)



        A a1 = new A(1);
        A a2 = new A(1);
        A a3 = a2;
        System.out.print("普通引用类型a1 == a2:");
        System.out.println(a1 == a2);//false
        System.out.println(a2 == a3);//true(对象赋给新对象连地址都是相同的)

        }
    }

   class A{
        int i;
        public A(int i){ 
            this.i = i;
        }

   }

equals和hashCode的区别

一个例子:

 1 class Test
 2 {
 3     private int num;
 4     private String data;
 5 
 6     public boolean equals(Object obj)
 7     {
 8         if (this == obj)
 9             return true;
10 
11         if ((obj == null) || (obj.getClass() != this.getClass()))
12             return false;
13 
           //能执行到这里,说明obj和this同类且非null。
14         Test test = (Test) obj;
15         return num == test.num&& (data == test.data || (data != null && data.equals(test.data)));
16     }
17 
18     public int hashCode()
19     {
20         //重写equals,也必须重写hashCode。具体后面介绍。
24     }
25 
26 }
(一)equals编写指导:

Test类对象有2个字段,num和data,这2个字段代表了对象的状态,他们也用在equals方法中作为评判的依据。

在第8行,传入的比较对象的引用和this做比较,这样做是为了 save time ,节约执行时间,如果this 和 obj是 对同一个堆对象的引用,那么,他们一定是equals 的。

接着,判断obj是不是为null,如果为null,一定不equals,因为既然当前对象this能调用equals方法,那么它一定不是null,非null 和 null当然不等价。

然后,比较2个对象的运行时类,是否为同一个类。不是同一个类,则不equals。getClass返回的是 this 和obj的运行时类的引用。如果他们属于同一个类,则返回的是同一个运行时类的引用。注意,一个类也是一个对象。

注意:

1、有些程序员使用下面的第二种写法替代第一种比较运行时类的写法。应该避免这样做。

第一种:
if((obj == null) || (obj.getClass() != this.getClass())) 

     return false; 

第二种:
if(!(obj instanceof Test)) 

     return false; // avoid 避免!

它违反了公约中的对称原则。

例如:假设Dog扩展了Aminal类。

dog instanceof Animal 得到true

animal instanceof Dog 得到false

这就会导致

animal.equls(dog) 返回true
dog.equals(animal) 返回false

仅当Test类没有子类的时候,这样做才能保证是正确的。

2、按照第一种方法实现,那么equals只能比较同一个类的对象,不同类对象永远是false。但这并不是强制要求的。一般我们也很少需要在不同的类之间使用equals。

3、在具体比较对象的字段的时候,对于基本值类型的字段,直接用 == 来比较(注意浮点数的比较,这是一个坑)对于引用类型的字段,你可以调用他们的equals,当然,你也需要处理字段为null 的情况。对于浮点数的比较,我在看Arrays.binarySearch的源代码时,发现了如下对于浮点数的比较的技巧:

if ( Double.doubleToLongBits(d1) == Double.doubleToLongBits(d2) ) //d1 和 d2 是double类型

if(  Float.floatToIntBits(f1) == Float.floatToIntBits(f2)  )      //f1 和 f2 是d2是float类型

4、并不总是要将对象的所有字段来作为equals 的评判依据,那取决于你的业务要求。比如你要做一个家电功率统计系统,如果2个家电的功率一样,那就有足够的依据认为这2个家电对象等价了,至少在你这个业务逻辑背景下是等价的,并不关心他们的价钱啊,品牌啊,大小等其他参数。

5、最后需要注意的是,equals 方法的参数类型是Object,不要写错!

(二)public int hashCode()编写指导:

这个方法返回对象的散列码,返回值是int类型的散列码。
对象的散列码是为了更好的支持基于哈希机制的Java集合类,例如 Hashtable, HashMap, HashSet 等。

关于hashCode方法,一致的约定是:
重写了euqls方法的对象必须同时重写hashCode()方法。

如果2个对象通过equals调用后返回是true,那么这个2个对象的hashCode方法也必须返回同样的int型散列码

如果2个对象通过equals返回false,他们的hashCode返回的值允许相同。(然而,程序员必须意识到,hashCode返回独一无二的散列码,会让存储这个对象的hashtables更好地工作。)

在上面的例子中,Test类对象有2个字段,num和data,这2个字段代表了对象的状态,他们也用在equals方法中作为评判的依据。那么, 在hashCode方法中,这2个字段也要参与hash值的运算,作为hash运算的中间参数。这点很关键,这是为了遵守:2个对象equals,那么 hashCode一定相同规则。

也是说,参与equals函数的字段,也必须都参与hashCode 的计算。

合乎情理的是:同一个类中的不同对象返回不同的散列码。典型的方式就是根据对象的地址来转换为此对象的散列码,但是这种方式对于Java来说并不是唯一的要求的
的实现方式。通常也不是最好的实现方式。

相比 于 equals公认实现约定,hashCode的公约要求是很容易理解的。有2个重点是hashCode方法必须遵守的。约定的第3点,其实就是第2点的
细化,下面我们就来看看对hashCode方法的一致约定要求。

第一:在某个运行时期间,只要对象的(字段的)变化不会影响equals方法的决策结果,那么,在这个期间,无论调用多少次hashCode,都必须返回同一个散列码。

第二:通过equals调用返回true 的2个对象的hashCode一定一样。

第三:通过equasl返回false 的2个对象的散列码不需要不同,也就是他们的hashCode方法的返回值允许出现相同的情况。

总结一句话:等价的(调用equals返回true)对象必须产生相同的散列码。不等价的对象,不要求产生的散列码相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值