Java中的==和equals
 
1.如果比较对象是值变量:只用==
 
2.如果比较对象是引用型变量:
     ==:比较两个引用是不是指向同一个对象实例。
     equals:
            首先Object类中equals的实现是直接调用了==操作。
            一个自定义类继承自Object且没有重写equals方法,那么其equals操作也是与Object类一样,仅仅是直接调用==操作。
            如果一个类重写过equals方法(或者继承自一个重写过equals方法的类),那么效果与==操作不同
    

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

 
检查两个引用型变量是否属于同一个Class:instanceof
          System.out.println((obj1 instanceof Student) && (obj2 instanceof Student)) 
 
 
API里的类大部分都重写了equals方法。例如String类

 
1>String类型的比较
       ==:比较两个str是否是指向同一个对象实例。
       equals:比较两个str中的内容是否相同
 
     对String的比较来说,还存在public String intern()方法。
     当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。
     它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
 
1 String a = new String("ab");
2 System.out.println(b.intern() == a.intern());
 

运行结果:false  true  true  false  true

由运行结果可以看出来,b.intern() == a和b.intern() == c可知
采用new 创建的字符串对象不进入字符串池,
字符串相加的时候,都是静态字符串的结果会添加到字符串池,如果其中含有变量(如f中的e)则不会进入字符串池中。
在定义变量的时候赋值,如果赋值的是静态的字符串,就会执行进入字符串缓冲池的操作,如果池中含有该字符串,则返回引用。
 
 


2>数据类型封装类的比较
 
Java为每一个简单数据类型提供了一个封装类,每个基本数据类型可以封装成对象类型。 除int(Integer)和char(Character),其余类型首字母大写即成封装类类型名。double (Double), float(Float),long(Long), short(Short),byte(Byte),boolean(Boolean).
  
以int和Integer为例说明  Java中int和Integer区别如下:
     1.int是基本的数据类型,默认值可以为0;Integer是int的封装类,默认值为null;
     2.int和Integer都可以表示某一个数值,但int和Integer不能够互用,因为他们两种不同的数据类型;
int a1=1;
int a2=1;
Integer b1 =new Integer (1);
Integer b2 =new Integer (1);
Answer:
a1==a2 这个是成立的,很简单,都知道
a1==b1 这个是不成立的.表达式的值为 false ,它们是不同的数据类型(在jdk1.5以上版本中为true)
b1==b2 这个也是不成立的.表达式的值为 false,虽然是相同的数据类型,但是它们是两个对象,==比较的是2个对象的地址,它们的地址是不相等的,内容相等都是1;
b1.equals(b2)==true 这个是成立的,表达式的值为 true. 相同数据类型,两个对象,地址不同,内容相同, quals比较的是2个对象的内容,所以成立。
(a.equals(b),因为equals比较的是两个对象,所以a,b都不能为基本数据类型,否则会出编译错误。)(在jdk1.5以上版本中,b可以为基本数据类型,a不可以) 同理,其它的封装类和基本类型也是这样

在jdk1.5以上的版本中,基本类型和封装类能自动转化,与String类型的对象和字符串常量类似。
        Integer i1 = 123;        
        Integer i2 = 123;
        int i = 123;         
        Integer i3 = new Integer(123);         Integer i4 = new Integer(123);                        
        System.out.println("i1 == i2 = "+(i1 == i2));
        System.out.println("i1.equals(i2) = "+(i1.equals(i2)));         
        System.out.println();
        System.out.println("i3 == i4 = "+(i3 == i4));
        System.out.println("i3.equals(i4) = "+(i3.equals(i4)));         
        System.out.println();
        System.out.println("i2 == i4 = "+(i2 == i4));
        System.out.println("i2.equals(i4) = "+(i2.equals(i4)));         
        System.out.println();
        System.out.println("i == i2 = "+(i == i2));
        System.out.println("i1.equals(i) = "+(i1.equals(i)));         
        System.out.println();
        System.out.println("i == i4 = "+(i == i4));
        System.out.println("i4.equals(i) = "+(i4.equals(i)));        
Answer:      
         i1 == i2 = true      
         i1.equals(i2) = true     
         i3 == i4 = false      
         i3.equals(i4) = true      
         i2 == i4 = false      
         i2.equals(i4) = true      
         i == i2 = true      
         i1.equals(i) = true      
         i == i4 = true    
         i4.equals(i) = true 

 

 
3>对象的hashcode和equals
 
1)理解hashcode的作用
     以java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去。下次做Object的比较或者取这个对象的时候,它会根据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程是这样:
1.new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去。
2.比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不同的话,肯定他们不能equal.

两个相等对象的equals方法一定为true, 但两个hashcode相等的对象不一定是相等的对象。

 
2)覆盖equals的时候总是要覆盖hashcode
     如果不覆盖hashcode的时候,可能会出现这样的情况,两个对象覆盖之后的equals方法返回为true,但其hashcode方法返回为false,而执行中的优化过程是,调用equals方法之前会先比较两个对象的hash值,如果不同,就不会进行equals比较了。所以覆盖equals方法而不覆盖hashcode方法存在上述风险,比较本应该放回equals的true但是在预执行hash值比较时就返回了false。
05-07 11:46