java之"equals"和"=="的区别
2014-10-17 18:47
567 查看
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。
实践是检验真理的唯一标准,所以来看下面的程序:
输出结果:
对于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(直接颠覆正常的理解):
运行结果:
看起来比较easy的问题为啥与我们想得不一致呢?(这就是为啥我在前文说Integer比较毁三观)
百度了一下发现原来Integer也实现了和String一样的对象池机制,Integer t1 = 1;实际上在编译的时候是将代码封装成:Integer t1 = Integer.valueOf(1);
源代码如下:
再来毁三观一次:
再来看看"+"运算:
再来看看Double的:
实际上:Byte,Short,Character,Integer,Boolean,Long都实现了常量池技术,只有两种浮点数:Double和Float没有实现常量池技术。另外Byte,Short,Character,Integer,Long这五种也只有在[-128,127]范围内才实现了常量池技术,超过了这个范围就不再使用常量池了。
当然对于基本数据类型,用"=="比较的就是值是否相等了。
接着再来看看自定义的类的比较:
尊重版权,转载请注明本文链接
欢迎关注行者摩罗微信公众号(xingzhemoluo),共同交流编程经验,扫描下方二维码即可;
基本数据类型包括: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。
实践是检验真理的唯一标准,所以来看下面的程序:
//验证 ==和equals,同时验证equals在自定义的对象时比较的结果 /** * @author 行者摩罗 */ public class EqualsTest { public static void main(String[] args) { String s1 = new String ("行者摩罗"); String s2 = new String ("行者摩罗"); String s3 = "行者摩罗"; String s4 = "行者摩罗"; String s5 = "行者"; String s6 = "摩罗"; String s7 = s5 + s6; //这种方式不会放入内存池,所以在用==比较s3和s7时返回false String s8 = "行者" + "摩罗"; //这种方式会放入内存池,实际上就等于创建了个"行者摩罗",所以用 ==比较s3和s8时是返回true String s9 = s5 + "摩罗"; //这种方式不会放入内存池,所以在用==比较s3和s9时返回false if (s1 == s2){ System.out.println("s1 == s2"); } else { System.out.println("s1 != s2");//对 } if (s1 == s3){ System.out.println("s1 == s3"); } else { System.out.println("s1 != s3");//对 } if (s3 == s2){ System.out.println("s3 == s2"); } else { System.out.println("s3 != s2");//对 } if (s3 == s4){ System.out.println("s3 == s4");//对 } else { System.out.println("s3 != s4"); } if (s7 == s8) { System.out.println("s7 == s8"); } else { System.out.println("s7 != s8");//对 } if (s7 == s9) { System.out.println("s7 == s9"); } else { System.out.println("s7 != s9");//对 } if (s8 == s9) { System.out.println("s8 == s9"); } else { System.out.println("s8 != s9");//对 } if (s3 == s8) { System.out.println("s3 == s8");//对 } else { System.out.println("s3 != s8"); } if (s3 == s7) { System.out.println("s3 == s7"); } else { System.out.println("s3 != s7");//对 } if (s1.equals(s2)){ System.out.println("s1.equals(s2)");//对 } if (s2.equals(s3)){ System.out.println("s2.equals(s3)");//对 } if (s1.equals(s3)){ System.out.println("s1.equals(s3)");//对 } if (s3.equals(s4)){ System.out.println("s3.equals(s4)");//对 } if (s7.equals(s8)){ System.out.println("s7.equals(s8)");//对 } if (s7.equals(s9)){ System.out.println("s7.equals(s9)");//对 } if (s8.equals(s9)){ System.out.println("s8.equals(s9)");//对 } Integer integer1 = new Integer(888); Integer integer2 = new Integer(888); if (integer1 == integer2) { System.out.println("integer1 == integer2"); } else { System.out.println("integer1 != integer2");//对 } if (integer1.equals(integer2)){ System.out.println("integer1.equals(integer2)");//对 } else { System.out.println("integer1 NotEquals integer2"); } } }
输出结果:
s1 != s2 s1 != s3 s3 != s2 s3 == s4 s7 != s8 s7 != s9 s8 != s9 s3 == s8 s3 != s7 s1.equals(s2) s2.equals(s3) s1.equals(s3) s3.equals(s4) s7.equals(s8) s7.equals(s9) s8.equals(s9) integer1 != integer2 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(直接颠覆正常的理解):
public class IntegerTest { public static void main(String[] args) { Integer t1 = 1; Integer t2 = 1; Integer t3 = new Integer (1); Integer t4 = new Integer (1); System.out.println("t1 == t2 :" + (t1 == t2)); System.out.println("t3 == t4 :" + (t3 == t4)); } }
运行结果:
t1 == t2 :true t3 == t4 :false
看起来比较easy的问题为啥与我们想得不一致呢?(这就是为啥我在前文说Integer比较毁三观)
百度了一下发现原来Integer也实现了和String一样的对象池机制,Integer t1 = 1;实际上在编译的时候是将代码封装成:Integer t1 = Integer.valueOf(1);
源代码如下:
/** * Returns a <tt>Integer</tt> instance representing the specified * <tt>int</tt> value. * If a new <tt>Integer</tt> instance is not required, this method * should generally be used in preference to the constructor * {@link #Integer(int)}, as this method is likely to yield * significantly better space and time performance by caching * frequently requested values. * * @param i an <code>int</code> value. * @return a <tt>Integer</tt> instance representing <tt>i</tt>. * @since 1.5 */ public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache return IntegerCache.cache[i + offset]; } return new Integer(i); }从源代码可知:通过Integer t1 = 1;这种方式创建,只要范围在[-128,127]之间,实际上JVM会在Integer的常量池里查找是否有1,如果存在就将该对象的引用返回,如果没有就创建一个对象并将该对象的引用返回。而"=="是比较对象的引用,所以"t1 == t2"返回的是true,而通过Integer t3 = new Integer(1);创建是每次都会创建一个新的对象,所以"t3 == t4"返回false;
再来毁三观一次:
public class IntegerTest { public static void main(String[] args) { Integer t1 = 400; Integer t2 = 400; Integer t3 = new Integer (400); Integer t4 = new Integer (400); System.out.println("t1 == t2 :" + (t1 == t2)); System.out.println("t3 == t4 :" + (t3 == t4)); } }输出结果:
t1 == t2 :false t3 == t4 :falset1 == t2输出false又毁三观了吧,这是因为只有范围在[-128,127]之间,才会采用常量池机制,如果超过这个范围,则Integer t1 = 400实际上就是按:Integer t1 = new Integer(400);这种方式创建的,所以输出false,涨知识了吧
再来看看"+"运算:
public class IntegerTest { public static void main(String[] args) { Integer t1 = 400; Integer t2 = 400; Integer t3 = new Integer (400); Integer t4 = new Integer (400); Integer t5 = 0; Integer t6 = new Integer (0); System.out.println("t1 == t2 :" + (t1 == t2 + t5)); System.out.println("t3 == t4 :" + (t3 == t4 + t6)); } }输出结果:
t1 == t2 :true t3 == t4 :true这回t1 == t2为啥又输出true了呢?这是因为java的数学运算都是在栈里进行的,JVM会对t4和t6进行拆箱操作,这就跟直接比较:400 = 400+0没区别。所以输出true。
再来看看Double的:
public class DoubleTest { public static void main(String[] args) { Double d1 = 1.0; Double d2 = 1.0; Double d3 = 0.0; Double d4 = new Double(1.0); Double d5 = new Double(1.0); Double d6 = new Double(0); System.out.println("d1 == t2 :" + (d1 == d2)); System.out.println("d4 == d5 :" + (d4 == d5 )); } }输出结果:
d1 == t2 :false d4 == d5 :false看完Integer再来看Double,同样是包装类型,"d1 == d2"却输出false,又毁三观了吧。这是因为Double没有实现常量池机制,所以通过"Double d1 = 1.0"实际上就跟通过:“Double d1 = new Double(1.0)”一样,所以输出false。
public class DoubleTest { public static void main(String[] args) { Double d1 = 1.0; Double d2 = 1.0; Double d3 = 0.0; Double d4 = new Double(1.0); Double d5 = new Double(1.0); Double d6 = new Double(0); System.out.println("d1 == t2 :" + (d1 == d2 + d3)); System.out.println("d4 == d5 :" + (d4 == d5 + d6)); } }输出结果:
d1 == t2 :true d4 == d5 :true输出true的原因同上,java加减乘除都是在栈中进行的,不再赘述。
实际上:Byte,Short,Character,Integer,Boolean,Long都实现了常量池技术,只有两种浮点数:Double和Float没有实现常量池技术。另外Byte,Short,Character,Integer,Long这五种也只有在[-128,127]范围内才实现了常量池技术,超过了这个范围就不再使用常量池了。
当然对于基本数据类型,用"=="比较的就是值是否相等了。
接着再来看看自定义的类的比较:
public class ObjectEquals { int i; ObjectEquals() {} ObjectEquals(int i) { this.i = i; } }
//验证 ==和equals,同时验证equals在自定义的对象时比较的结果 /** * @author 行者摩罗 */ public class EqualsTest { public static void main(String[] args) { // 比较自定义的类的对象 ObjectEquals o1 = new ObjectEquals(); ObjectEquals o2 = new ObjectEquals(); o1.i = o2.i = 8; if (o1 == o2) { System.out.println("o1 == o2"); } else { System.out.println("o1 != o2");// 对 } if (o1.equals(o2)) { System.out.println("o1.equals(o2)"); } else { System.out.println("o1 NotEquals o2");// 对 } ObjectEquals o3 = new ObjectEquals(8); ObjectEquals o4 = new ObjectEquals(8); if (o3 == o4) { System.out.println("o3 == o4"); } else { System.out.println("o3 != o4");// 对 } if (o3.equals(o4)) { System.out.println("o3.equals(o4)"); } else { System.out.println("o3 NotEquals o4");// 对 } } }输出结果:
o1 != o2 o1 NotEquals o2 o3 != o4 o3 NotEquals o4解释一下结果;对于自定义的类,由于ObjectEquals类我没有重写equals方法,所以当EqualsTest对ObjectEquals类型的对象进行比较的时候默认使用的是从Object类继承过来的equals()方法。而Object类的equals()方法代码如下:
boolean equals(Object o) { return this == o; }所以如果没有重写equals()方法的话,那么在EqualsTest中使用equals()方法就跟使用"=="是一样的,也就是比较两个变量指向的对象是否是同一个对象,所以比较两个独立的对象返回的当然是false,如果想比较值,就必须重写equals()方法。
尊重版权,转载请注明本文链接
欢迎关注行者摩罗微信公众号(xingzhemoluo),共同交流编程经验,扫描下方二维码即可;
相关文章推荐
- Java中"equals"和"=="的区别
- java中"=="和equals方法究竟有什么区别?
- Java中"equals"和"=="的区别
- Java杂谈之String----"=="与equals的区别
- java中"==" 和 equals区别
- java 中,"=="和 "equals"的区别
- Java中"=="与equals()方法的区别
- java中"=="和equals()的区别
- Java基础回顾: "=="和equals()方法的区别
- java装箱和拆箱已及"=="与"equals"的区别
- Java中的String str="abc"; String str=new String("abc");和String str = new String();的区别以及==与equals()的不同。
- Java中"equals"和"=="的区别
- Java "equals"和"=="的区别
- Java中"=="和"equals"区别
- Java中equals与"=="的使用区别
- Java中"=="与equals()方法的区别
- "==" 和 equals的区别 java 日期Date类的使用 自动装箱和自动拆箱
- "=="和equals方法有什么区别
- "=="和equals方法究竟有什么区别?
- "=="和equals方法究竟的区别?