java中的“==”,equals()和hashcde的区别

1、 ==

java中的数据类型,可分为两类:

 1、基本数据类型,也称原始数据类型

  byte,short,char,int,long,float,double,boolean 他们 之间的比较,应用(==),比较的是他们的值。

    2、引用类型(类i,接口,数组)

  当他们用(==)进行比较的时候,比较的 是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的记过位true,否则比较后结果为false。

  对象是放在堆中的,栈中存放的是对象的引用(地址)。由此可见“==”是对栈 中的值进行比较的。如果要比较堆中对象的内容是否想用,那么就要充血equals方法了。

 1 public static void main(String[] args){
 2     int int1=12;
 3     int int2=12;
 4     Integer Integer1 = new integer(12);
 5     Integer Integer2 =new Integer(12);
 6     Integer Integer3  = new Integer(12);
 7     Integer a1 =127 8     Integer b1 = 127 9     Integer  a  =12810     Integer   b=12811     String s1 = "str";
12     String  s2 = "str";
13     String str1 =new String(“str”);
14     String str2 =new String(“str”)
15 
16      System.out,println(“int1==int2”+(int1==int2));
17      System.out,println("int1==integer1+"(int1==integer1));
18      System.out,println("Integer1==Integer2"+(Integer1==Integer2));
19      System.out,println("Integer3==b1"+(Integer3==b1));
20      System.out,println("a1==b1"+(a1==b1));
21      System.out,println("a=b"+(a==b));
22      System.out,println("s1==s2"+(s1==s2));
23      System.out,println("s1==str1"+()s1==str1);
24      System.out,println("str1==str2"+(str1==str2));
25  }                       

输出结果:

int1==int2  true

int1==Integer1;true//Innteger会自动拆箱为int,所以true;(当Integer与int进行==比较是,Integer会拆箱成一个int类型,所以还是相当于两个int型比较,这里的Integer,不管是直接赋值,还是new创建的对象,质押跟int比较就会拆箱为int类型,所以是相等的)

Integer1==Integer2;  false//是不同的对象,在内存中的存放地址不同(这是两个对象类型,而且不会进行拆箱比较),所以为false

Integer3==b1;  false//integer3是一个对象类型,而b1是一个常量他们存放内存的位置不一样,素以也不等.

a1==b1;   //true

a==b;   //false      这是因为Integer作为常量是,对于-128到127之间的数,会进行缓存,也即是说int a1=127时,在 范围之内,这个时候就存放在缓存中,挡再创建a时,java发现缓存中存在127这个数了,就直接取出来赋值给a,所以a1==b1.当超过范围就是 new integer()来new一个对象了,所以a,b都是new Integer(128)出来的变量,所以他们不等 .

s1==s2;  true//java中唯一不需要new'既可以产生对象的途径 ,这种形式的赋值称为直接量,他被存放在一个叫字符串拘留池(常量池)的地方;而new创建的对象都放在堆上.

(什么是字符串拘留?当我们声明一个字符串String s="hello"时,JVM会先从常量池中查找又没哟值为"Hello"的对象,如果有,会把该对象赋给当前引用,也就是说原来的引用和现在的引用指向同一个对象;如果没有,则在拘留池中创建一个值为"Hello"的对象,如果下一次还有类似的语句,例如String str="Hello"时,又会指向"Hello"这个对象,以这种形式声明字符串,无论有多少个都指向同一个底线)

s1==str1;false//    以new这种形式创建的对象,每执行一次就生成一个新对象,是两个独立对象

str1==str2;false//

 

2、要是类中覆盖了equals方法,那么就u要根据具体的代码来是却抵inequals方法的作用了,覆盖后一般都是通过对象的内容是否想等来判断对象是否想等。下面对equals进行重写。

 1 public boolean equals(Object anObject){
 2      if (this==anObject){
 3          return true;
 4 }
 5     if(anObject insrtanceof Striing){//instancef操纵检查符
 6         String anotherString = (String)anObject;
 7         int n = cont;
 8         if(n==anotherString.count){
 9         char  v1[] = values;
10         char  v2[]=anotherString.value;
11         int i  = offset;
12         int j = anotherString.value;
13         while (n--!=0){
14               f(v1[I++]!=v2[j++])
15               return false;
16 }
17         return  true;}
18 } 
19
20 retrn false; 

}

即String中equals方法判断相等的步骤是:

1、若A==B即是同一个String对象,返回true;

2、若对比对象是String类型则继续,否则返回ufalse;

3、判断A、B长的是否一样,不一样的话返回false

4、逐个字符比较,若有不相等字符,返回false

 

这里对equals需要注意我五点:

1、自反性:对人一引用值x,x.equals(x)的返回值一定为true;

2、对称性:对于任何引用值x,y当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值应为true;

3、传递性:如果.x.equals(y)=true,y.equals(z)=true,则x.equals(z)=true

4、一致性:若参与比较的对象没有任何改变,则对象比较的结果哦也不应有任何改变

5、非空性:任何非空的引用值x,x.equals(null)的返回值一定为false;

 

实现高质量equals方法的诀窍:

1、使用==符号检查“参数是否为这个对象的引用“。如果是,则返回true。这只不过是一种性能优化,如果比价操作有可能很昂贵,就值得 这么做。

2、使用instancef操作符检查”参数是否为正确的类型“。如果不是,则返回false。一般来说,所谓”正确的类型“是指equals方法所在的那个类。

3、把参数转换陈正确的类型。因为转换之前进行过instanceof测试,素偶一确保会成功。

4、对于该类中的每个”关键“域,检查参数中的域是否与该对象中对应的域相匹配。如果 这些 测试全部成功,则返回true,否则false;

5、当编写完成了equals方法之后,检查”对称性“,”传递性“,”一致性“。

 

 

3、hashCode

hashCode()方法返回的就是一个数值,生成一个hash码,主要用途就是对对象进行散列的时候作为key输入,hashCode方法实际上返回的就是对象存储的屋里地址(实际上并不是真正的内存的物理地址)

散列函数,散列算法,哈希函数是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数将任意长度的二进制值映射位较短的固定长度的二进制值,这个小的二进制值称为哈希值,好的散列函数在啊输入域中很少出现散列冲突。

所有散列函数都有如下一个基本特征:

1:如果a=b,则h(a)=h(b)。

2:如果a!=b,则h(a)与h(b)可能得到相同 的三列支散列值。

hashCode的作用:Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者无序,但元素不可重复。

要想保证袁术不重复,可拉ing个是否重复应该依据什么来判断,可以使用Object。equals方法,但是当元素很多的时候,后添加到集合中的元素比较的次数就非常多来,也就是说,如果集合中现在已经有2000个元素,那么第2001个元素加入集合是,他就要调用2000次equals方法,这显然会大大降低效率,所以Java采用来哈希表的原理。如此一来先吊用这个元素的hashCode方法,就一下子能定位倒他应该放置的屋里位置上;如果这个位置上没有元素,就直接存储在这个位置上,不用再进行任何比较;如果这个位置上已经有元素来,就调用它的equals方法与新元素进行比较,相同的话就不存,不相同就散列其他的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低来,几乎只需要一两次。

4、equals方法和hashCode方法关系

Java对于equals放大和hashCode方法是这样规定的:

(1)同一对象上对此调用hashCode()方法,总是返回相同的整型值。

(2)如果a.equals(b),则一定有a.hashCode()一定等于b.hashCode()。

(3)如果!a.equals(b),则a.hashCode()不一定等于b.hashCode()。此时如果a.hashCode()总是不等于b.hashCode(),会提高hashtables的性能。

(4)a.hashCode()==b.hahsCode(),则a.equals(b)可真可假。

(5)a.hashCode()!=b.hashCode(),则a.equals(b)为假

结论:

1、如果两个对象equals,java运行时环境会认为他们的hashCode一定想等。

2、如果两个对象不equals,他们的hashCode有可能想等。

3、如果两个对象hashCode想等,他们不一定equals。

4、如果两个对象hashCode不想等,他们一定不equals。

 关于这两个方法的重要规范

规范一:若要重写equals(Object obj)方法,有必要重写hashCode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashCode()返回值,简单来说“如果两个对象相同,那么他们的hashCOde应该想等”。不过应该注意:这个只上规范,如果你非要写一个类让equals(Object obj)返回true而hashCode()返回两个不想等的值,编译和运行都是不会报错的,不过这样违反了Java规范,程序也就埋下了BUG

规范二:如果equals(Object obj)返回false,既两个对象”不相同“,并不要求对这两个对象调用hashCode()方法得到阿玲个不相同的数,也就是”如果两个对象不相同,他的hashCode可能相同“。

 

 

5、 总结:

  1、equal方法用于比较对象的内容是否想等(覆盖以后)

  2、hashCode方法只有在集合中用到

  3、当覆盖了equals方法时,比较对象是否想等将通过覆盖后的equals方法进行比较(判断对象的内容是否想等)。

  4、将对象放入到集合中是,首先判断要放入对象的hashCode值与集合中任意一个元素的hashCode值是否想等,如果不想等直接将该对象放入集合中,如果hashCode值想等,然后再通过equals方法判断equals方法判断要入对象与集合中的任意一个对象是否想等,如果equals判断不想等,直接将该元素放入到集合中,否则不放入。

 

posted @ 2020-04-21 13:56  pickGo  阅读(234)  评论(0编辑  收藏  举报