java之"equals"和"=="的区别

转载至:http://blog.csdn.net/xingzhemoluo/article/details/40189419


        java中的数据类型有基本数据类型和引用数据类型。

        基本数据类型包括:int,char,float,long,double,boolean,byte,short(注:String不是基本数据类型);基本数据类型之间的比较用"=="。

        引用数据类型包括:Integer,Char,Float,Long,Double,Boolean,Byte,Short。引用数据类型“==”比较的是他们在内存中的存放地址,equals比较的是值是否相等。

        对于String和Integer这两种类型来说,由于他俩的创建方式有两种:a.使用构造器 b.不使用构造器,所以它俩比较特殊。String s1 = "行者摩罗";String s2 = "行者摩罗";此时"s1 == s2"的结果为true。String s1 = new String("行者摩罗");String s2 = new String("行者摩罗");此时"s1 == s2"的结果为false。同理:Integer t1 = 1; Integer t2 = 1;此时"t1 == t2"的结果为true。Integer t1 = new Integer(1); Integer t2 = new Integer(1);此时"t1 == t2"的结果为false。

        实践是检验真理的唯一标准,所以来看下面的程序:

[java]  view plain  copy
 print ?
  1. //验证 ==和equals,同时验证equals在自定义的对象时比较的结果  
  2. /** 
  3.  * @author 行者摩罗 
  4.  */  
  5. public class EqualsTest {     
  6.     public static void main(String[] args) {  
  7.         String s1 = new String ("行者摩罗");  
  8.         String s2 = new String ("行者摩罗");  
  9.         String s3 = "行者摩罗";  
  10.         String s4 = "行者摩罗";  
  11.         String s5 = "行者";  
  12.         String s6 = "摩罗";  
  13.         String s7 = s5 + s6;        //这种方式不会放入内存池,所以在用==比较s3和s7时返回false  
  14.         String s8 = "行者" + "摩罗";  //这种方式会放入内存池,实际上就等于创建了个"行者摩罗",所以用 ==比较s3和s8时是返回true  
  15.         String s9 = s5 + "摩罗";     //这种方式不会放入内存池,所以在用==比较s3和s9时返回false  
  16.         if (s1 == s2){  
  17.             System.out.println("s1 == s2");  
  18.         } else {  
  19.             System.out.println("s1 != s2");//对  
  20.         }  
  21.           
  22.         if (s1 == s3){  
  23.             System.out.println("s1 == s3");  
  24.         } else {  
  25.             System.out.println("s1 != s3");//对  
  26.         }  
  27.           
  28.         if (s3 == s2){  
  29.             System.out.println("s3 == s2");  
  30.         } else {  
  31.             System.out.println("s3 != s2");//对  
  32.         }  
  33.         if (s3 == s4){  
  34.             System.out.println("s3 == s4");//对  
  35.         } else {  
  36.             System.out.println("s3 != s4");  
  37.         }  
  38.         if (s7 == s8) {  
  39.             System.out.println("s7 == s8");  
  40.         } else {  
  41.             System.out.println("s7 != s8");//对  
  42.         }  
  43.         if (s7 == s9) {  
  44.             System.out.println("s7 == s9");  
  45.         } else {  
  46.             System.out.println("s7 != s9");//对  
  47.         }  
  48.         if (s8 == s9) {  
  49.             System.out.println("s8 == s9");  
  50.         } else {  
  51.             System.out.println("s8 != s9");//对  
  52.         }  
  53.         if (s3 == s8) {  
  54.             System.out.println("s3 == s8");//对  
  55.         } else {  
  56.             System.out.println("s3 != s8");  
  57.         }  
  58.         if (s3 == s7) {  
  59.             System.out.println("s3 == s7");  
  60.         } else {  
  61.             System.out.println("s3 != s7");//对  
  62.         }  
  63.           
  64.         if (s1.equals(s2)){  
  65.             System.out.println("s1.equals(s2)");//对  
  66.         }   
  67.           
  68.         if (s2.equals(s3)){  
  69.             System.out.println("s2.equals(s3)");//对  
  70.         }   
  71.           
  72.         if (s1.equals(s3)){  
  73.             System.out.println("s1.equals(s3)");//对  
  74.         }  
  75.         if (s3.equals(s4)){  
  76.             System.out.println("s3.equals(s4)");//对  
  77.         }  
  78.         if (s7.equals(s8)){  
  79.             System.out.println("s7.equals(s8)");//对  
  80.         }  
  81.         if (s7.equals(s9)){  
  82.             System.out.println("s7.equals(s9)");//对  
  83.         }  
  84.         if (s8.equals(s9)){  
  85.             System.out.println("s8.equals(s9)");//对  
  86.         }  
  87.         Integer integer1 = new Integer(888);  
  88.         Integer integer2 = new Integer(888);  
  89.         if (integer1 == integer2) {  
  90.             System.out.println("integer1 == integer2");  
  91.         } else {  
  92.             System.out.println("integer1 != integer2");//对  
  93.         }  
  94.         if (integer1.equals(integer2)){  
  95.             System.out.println("integer1.equals(integer2)");//对  
  96.         } else {  
  97.             System.out.println("integer1 NotEquals integer2");  
  98.         }  
  99.     }  
  100. }  

输出结果:

[java]  view plain  copy
 print ?
  1. s1 != s2  
  2. s1 != s3  
  3. s3 != s2  
  4. s3 == s4  
  5. s7 != s8  
  6. s7 != s9  
  7. s8 != s9  
  8. s3 == s8  
  9. s3 != s7  
  10. s1.equals(s2)  
  11. s2.equals(s3)  
  12. s1.equals(s3)  
  13. s3.equals(s4)  
  14. s7.equals(s8)  
  15. s7.equals(s9)  
  16. s8.equals(s9)  
  17. integer1 != integer2  
  18. integer1.equals(integer2)  
         由输出结果可知:"=="比较的是它俩是否指向同一个引用,"equlas"比较的是它俩的值是否相等。

         对于String s3 = "行者摩罗";这种方式实际上是将“行者摩罗”存入了常量池,当再创建String s4 = "行者摩罗";时,首先JVM先到常量池里寻找常量池里是否有"行者摩罗"这个字符串,如果没有就创建一个新的字符串存入常量池,然后将地址赋值给s4;如果已经有了,就将常量池里"行者摩罗"对应的地址赋给s4,显然这里是将地址赋值给s4了,所以这里的s3和s4都指向同一片内存区域,所以s3 == s4输出的是true。对于String s8 = "行者" + "摩罗"这种创建方式实际上就等同于String s8 = "行者摩罗";所以s8的指向的引用还是与s3指向的引用是相同的。而对于String s7 = s5 + s6;以及String s9 = s5 + “摩罗”;这两种创建方式,实际上是采用构造器了,即通过new String()的方式一样,故用s3 == s7和s == s9比较时输出的结果都是false。

        上面写完String类型的,接着再来看看“毁三观”的Integer(直接颠覆正常的理解):

[java]  view plain  copy
 print ?
  1. public class IntegerTest {  
  2.     public static void main(String[] args) {  
  3.         Integer t1 = 1;  
  4.         Integer t2 = 1;  
  5.         Integer t3 = new Integer (1);  
  6.         Integer t4 = new Integer (1);  
  7.         System.out.println("t1 == t2 :" + (t1 == t2));  
  8.         System.out.println("t3 == t4 :" + (t3 == t4));  
  9.     }  
  10. }  

运行结果:

[java]  view plain  copy
 print ?
  1. t1 == t2 :true  
  2. t3 == t4 :false  

看起来比较easy的问题为啥与我们想得不一致呢?(这就是为啥我在前文说Integer比较毁三观)

         百度了一下发现原来Integer也实现了和String一样的对象池机制,Integer t1 = 1;实际上在编译的时候是将代码封装成:Integer t1 = Integer.valueOf(1);

         源代码如下:

[java]  view plain  copy
 print ?
  1. /** 
  2.      * Returns a <tt>Integer</tt> instance representing the specified 
  3.      * <tt>int</tt> value. 
  4.      * If a new <tt>Integer</tt> instance is not required, this method 
  5.      * should generally be used in preference to the constructor 
  6.      * {@link #Integer(int)}, as this method is likely to yield 
  7.      * significantly better space and time performance by caching 
  8.      * frequently requested values. 
  9.      * 
  10.      * @param  i an <code>int</code> value. 
  11.      * @return a <tt>Integer</tt> instance representing <tt>i</tt>. 
  12.      * @since  1.5 
  13.      */  
  14.     public static Integer valueOf(int i) {  
  15.     final int offset = 128;  
  16.     if (i >= -128 && i <= 127) { // must cache   
  17.         return IntegerCache.cache[i + offset];  
  18.     }  
  19.         return new Integer(i);  
  20.     }  
       从源代码可知:通过Integer t1 = 1;这种方式创建,只要范围在[-128,127]之间,实际上JVM会在Integer的常量池里查找是否有1,如果存在就将该对象的引用返回,如果没有就创建一个对象并将该对象的引用返回。而"=="是比较对象的引用,所以"t1 == t2"返回的是true,而通过Integer t3 = new Integer(1);创建是每次都会创建一个新的对象,所以"t3 == t4"返回false;

      再来毁三观一次:

[java]  view plain  copy
 print ?
  1. public class IntegerTest {  
  2.     public static void main(String[] args) {  
  3.         Integer t1 = 400;  
  4.         Integer t2 = 400;  
  5.         Integer t3 = new Integer (400);  
  6.         Integer t4 = new Integer (400);  
  7.         System.out.println("t1 == t2 :" + (t1 == t2));  
  8.         System.out.println("t3 == t4 :" + (t3 == t4));  
  9.     }  
  10. }  
输出结果:
[java]  view plain  copy
 print ?
  1. t1 == t2 :false  
  2. t3 == t4 :false  
     t1 == t2输出false又毁三观了吧,这是因为只有范围在[-128,127]之间,才会采用常量池机制,如果超过这个范围,则Integer t1 = 400实际上就是按:Integer t1 = new Integer(400);这种方式创建的,所以输出false,涨知识了吧 大笑

再来看看"+"运算:
[java]  view plain  copy
 print ?
  1. public class IntegerTest {  
  2.     public static void main(String[] args) {  
  3.         Integer t1 = 400;  
  4.         Integer t2 = 400;  
  5.         Integer t3 = new Integer (400);  
  6.         Integer t4 = new Integer (400);  
  7.         Integer t5 = 0;  
  8.         Integer t6 = new Integer (0);  
  9.         System.out.println("t1 == t2 :" + (t1 == t2 + t5));  
  10.         System.out.println("t3 == t4 :" + (t3 == t4 + t6));  
  11.     }  
  12. }  
输出结果:
[java]  view plain  copy
 print ?
  1. t1 == t2 :true  
  2. t3 == t4 :true  
       这回t1 == t2为啥又输出true了呢?这是因为java的数学运算都是在栈里进行的,JVM会对t4和t6进行拆箱操作,这就跟直接比较:400 = 400+0没区别。所以输出true。


再来看看Double的:

[java]  view plain  copy
 print ?
  1. public class DoubleTest {  
  2.     public static void main(String[] args) {  
  3.         Double d1 = 1.0;  
  4.         Double d2 = 1.0;  
  5.         Double d3 = 0.0;  
  6.         Double d4 = new Double(1.0);  
  7.         Double d5 = new Double(1.0);  
  8.         Double d6 = new Double(0);  
  9.         System.out.println("d1 == t2 :" + (d1 == d2));  
  10.         System.out.println("d4 == d5 :" + (d4 == d5 ));  
  11.     }  
  12. }  
输出结果:

[java]  view plain  copy
 print ?
  1. d1 == t2 :false  
  2. d4 == d5 :false  
看完Integer再来看Double,同样是包装类型,"d1 == d2"却输出false,又毁三观了吧。这是因为Double没有实现常量池机制,所以通过"Double d1 = 1.0"实际上就跟通过:“Double  d1 = new Double(1.0)”一样,所以输出false。
[java]  view plain  copy
 print ?
  1. public class DoubleTest {  
  2.     public static void main(String[] args) {  
  3.         Double d1 = 1.0;  
  4.         Double d2 = 1.0;  
  5.         Double d3 = 0.0;  
  6.         Double d4 = new Double(1.0);  
  7.         Double d5 = new Double(1.0);  
  8.         Double d6 = new Double(0);  
  9.         System.out.println("d1 == t2 :" + (d1 == d2 + d3));  
  10.         System.out.println("d4 == d5 :" + (d4 == d5 + d6));  
  11.     }  
  12. }  
输出结果:
[java]  view plain  copy
 print ?
  1. d1 == t2 :true  
  2. d4 == d5 :true  
输出true的原因同上,java加减乘除都是在栈中进行的,不再赘述。


        实际上:Byte,Short,Character,Integer,Boolean,Long都实现了常量池技术,只有两种浮点数:Double和Float没有实现常量池技术。另外Byte,Short,Character,Integer,Long这五种也只有在[-128,127]范围内才实现了常量池技术,超过了这个范围就不再使用常量池了。

         当然对于基本数据类型,用"=="比较的就是值是否相等了。

         接着再来看看自定义的类的比较:

[java]  view plain  copy
 print ?
  1. public class ObjectEquals {  
  2.     int i;  
  3.     ObjectEquals() {}  
  4.     ObjectEquals(int i) {  
  5.         this.i = i;  
  6.     }  
  7. }  
[java]  view plain  copy
 print ?
  1. //验证 ==和equals,同时验证equals在自定义的对象时比较的结果  
  2. /** 
  3.  * @author 行者摩罗 
  4.  */  
  5. public class EqualsTest {  
  6.     public static void main(String[] args) {  
  7.         // 比较自定义的类的对象  
  8.         ObjectEquals o1 = new ObjectEquals();  
  9.         ObjectEquals o2 = new ObjectEquals();  
  10.         o1.i = o2.i = 8;  
  11.         if (o1 == o2) {  
  12.             System.out.println("o1 == o2");  
  13.         } else {  
  14.             System.out.println("o1 != o2");// 对  
  15.         }  
  16.   
  17.         if (o1.equals(o2)) {  
  18.             System.out.println("o1.equals(o2)");  
  19.         } else {  
  20.             System.out.println("o1 NotEquals o2");// 对  
  21.         }  
  22.   
  23.         ObjectEquals o3 = new ObjectEquals(8);  
  24.         ObjectEquals o4 = new ObjectEquals(8);  
  25.   
  26.         if (o3 == o4) {  
  27.             System.out.println("o3 == o4");  
  28.         } else {  
  29.             System.out.println("o3 != o4");// 对  
  30.         }  
  31.   
  32.         if (o3.equals(o4)) {  
  33.             System.out.println("o3.equals(o4)");  
  34.         } else {  
  35.             System.out.println("o3 NotEquals o4");// 对  
  36.         }  
  37.     }  
  38. }  
输出结果:

[java]  view plain  copy
 print ?
  1. o1 != o2  
  2. o1 NotEquals o2  
  3. o3 != o4  
  4. o3 NotEquals o4  
      解释一下结果;对于自定义的类,由于ObjectEquals类我没有重写equals方法,所以当EqualsTest对ObjectEquals类型的对象进行比较的时候默认使用的是从Object类继承过来的equals()方法。而Object类的equals()方法代码如下:  
[java]  view plain  copy
 print ?
  1. boolean equals(Object o) {  
  2. return this == o;  
  3. }  
所以如果没有重写equals()方法的话,那么在EqualsTest中使用equals()方法就跟使用"=="是一样的,也就是比较两个变量指向的对象是否是同一个对象,所以比较两个独立的对象返回的当然是false,如果想比较值,就必须重写equals()方法。

尊重版权,转载请注明本文链接


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值