java中 == 与 equal 的区别

本文详细解析了Java中equals方法与==运算符的区别,包括它们在字符串、基本类型及包装类中的应用,并通过示例代码展示了两者在不同场景下的表现。

第一个博客

String a = "123";// 常量 存在常量区,如果没有则创建,如果有则拿来使用
String b = "123";// 常量 存在常量区
String c = new String("123");// 存储在堆中,只要见到new,就是在堆中开辟新的空间存储内容
String d = new String("123");// 存储在堆中


== 比较的是地址


a==b -》 true  因为都在常量区的同一块存储区域(存储地址相同),故相等
a==c -》false  存储区域都不一样,不可能地址相同
c==d -》false  两个都是new,都是新开辟空间存储内容,故地址不可能一样


那么在我们判断字符串值相等时使用什么?equals比较的是字符串的值
equals方法
a.equals(b) = true
a.equals(c) = true
c.equals(d) = true


如上equals方法仅对字符串有效

废话不多说了,开门见山吧,先来看一段代码:

复制代码
String str1 = new String("str");
        String str2 = new String("str");
        System.out.println("==比较 :"+ (str1 == str2));
        System.out.println("equal比较:"+ str1.equals(str2));
        String str3 = "str1";
        String str4 = "str1";
        System.out.println("==比较 :"+ (str3 == str4));
        System.out.println("equal比较:"+ str3.equals(str4));
复制代码

输出的答案:

以上的输出结果有误,应该是

false

equal比较:true

true

equal比较:true

 

根据打印的可以发现使用equal比较时无论是使用自动装箱来实例化还是用new来实例化,返回的都true,而用==则不一样了,自动装箱来实例化的返回的是true,而用new来

实例化的返回的确实false;先不急着解决为什么,先来了解下equals和==的区别,到时候就可以知道答案了

equals方法最初是在所有类的基类Object中进行定义的,源码是

 public boolean equals(Object obj) {
    return (this == obj);
    }

可以看出这里定义的equals与==是等效的,但上面的怎么还会不一样呢?
原因就是String类对equals进行了重写:

复制代码
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = offset;
        int j = anotherString.offset;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
            return false;
        }
        return true;
        }
    }
    return 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 

经过重写后就跟==有本质的区别了:

equal:是用来比较两个对象内部的内容是否相等的,由于所有的类都是继承自java.lang.Object类的,所以如果没有对该方法进行覆盖的话,调用
的仍然是Object类中的方法,而Object中的equal方法返回的却是==的判断,因此,如果在没有进行该方法的覆盖后,调用该方法是没有
任何意义的。在java面向对象的处理中我们一般在javabean中都要选择重写equals方法,使用hibernate后,我们要生成数据库的映射文件与实体

类,这是我们就最好在实体类中进行equals方法的重写,重写时我们可以根据自己的定义来实现该方法只要遵守那五条原则,例如对于一个student类

我们定义只要在学号相同时我们就认为这两个对象时相等的;同时我们还要重写hashcode方法http://www.cnblogs.com/shenliang123/archive/2012/04/16/2452206.html
==:是用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。


第二个博客:


java equal和==的比较,尤其注意基本类型和基本类型的包装类型的比较
java中equals方法和“==”的区别: 

equals 方法是 java.lang.Object 类的方法。 

有两种用法说明: 

(1)对于字符串变量来说,使用“==”和“equals()”方法比较字符串时,其比较方法不同。 

“==”比较两个变量本身的值,即两个对象在内存中的首地址。 

“equals()”比较字符串中所包含的内容是否相同。 

比如: 

String s1,s2,s3 = "abc", s4 ="abc" ; 

s1 = new String("abc"); 

s2 = new String("abc"); 

那么: 

s1==s2 是 false //两个变量的内存地址不一样,也就是说它们指向的对象不 一样, 

故不相等。 

s1.equals(s2) 是 true //两个变量的所包含的内容是abc,故相等。 

注意(1): 

如果: StringBuffer s1 = new StringBuffer("a"); 
StringBuffer s2 = new StringBuffer("a"); 


结果: s1.equals(s2) //是false 

解释:StringBuffer类中没有重新定义equals这个方法,因此这个方法就来自Object类, 


而Object类中的equals方法是用来比较“地址”的,所以等于false. 

注意(2): 

对于s3和s4来说,有一点不一样要引起注意,由于s3和s4是两个字符 

串常量所生成的变量,其中所存放的内存地址是相等的, 

所以s3==s4是true(即使没有s3=s4这样一个赋值语句) 


(2)对于非字符串变量来说,"=="和"equals"方法的作用是相同的都是用来比较其 

对象在堆内存的首地址,即用来比较两个引用变量是否指向同一个对象。 

比如: 

class A 



A obj1 = new A(); 

A obj2 = new A(); 



那么:obj1==obj2是false 

obj1.equals(obj2)是false 

但是如加上这样一句:obj1=obj2; 

那么 obj1==obj2 是true 

obj1.equals(obj2) 是true 

总之:equals方法对于字符串来说是比较内容的,而对于非字符串来说是比较 

其指向的对象是否相同的。 

== 比较符也是比较指向的对象是否相同的也就是对象在对内存中的的首地址。 

String类中重新定义了equals这个方法,而且比较的是值,而不是地址。所以是true。 



关于equals与==的区别从以下几个方面来说: 

(1)如果是基本类型比较,那么只能用==来比较,不能用equals 

比如: 
public class TestEquals { 
public static void main(String[] args) 

int a = 3; 
int b = 4; 
int c = 3; 
System.out.println(a == b);//结果是false 
System.out.println(a == c);//结果是true 
System.out.println(a.equals(c));//错误,编译不能通过,equals方法 
//不能运用与基本类型的比较 



(2)对于基本类型的包装类型,比如Boolean、Character、Byte、Shot、Integer、Long、Float、Double等的引用变量,==是比较地址的,而equals是比较内容的。比如: 
public class TestEquals { 
public static void main(String[] args) 
{ Integer n1 = new Integer(30); 
Integer n2 = new Integer(30); 
Integer n3 = new Integer(31); 
System.out.println(n1 == n2);//结果是false 两个不同的Integer对象,故其地址不同, 
System.out.println(n1 == n3);//那么不管是new Integer(30)还是new Integer(31) 结果都显示false 
System.out.println(n1.equals(n2));//结果是true 根据jdk文档中的说明,n1与n2指向的对象中的内容是相等的,都是30,故equals比较后结果是true 
System.out.println(n1.equals(n3));//结果是false 因对象内容不一样,一个是30一个是31 


这是Integer的实例,如果是其他的比如Double、Character、Float等也一样。 

(3)注意:对于String(字符串)、StringBuffer(线程安全的可变字符序列)、StringBuilder(可变字符序列)这三个类作进一步的说明。 
(a)首先,介绍String的用法,请看下面的实例: 
public class TestEquals { 
public static void main(String[] args) { 
String s1 = "123"; 
String s2 = "123"; 
String s3 = "abc"; 
String s4 = new String("123"); 
String s5 = new String("123"); 
String s6 = new String("abc"); 

System.out.println(s1 == s2);//(1)true 
System.out.println(s1.equals(s2));//(2)true 
System.out.println(s1 == s3);//(3)flase 
System.out.println(s1.equals(s3));//(4)flase 

System.out.println(s4 == s5);//(5)flase 
System.out.println(s4.equals(s5));//(6)true 
System.out.println(s4 == s6);//(7)flase 
System.out.println(s4.equals(s6));//(8)flase 

System.out.println(s1 == s4);//(9)false 
System.out.println(s1.equals(s4));//(10)true 



答案解释:s1与s2分别指向由字符串常量”123” 创建的对象,在常量池中,只有一个对象,内容为123,有两个引用s1和s2指向这个对象,故这两个引用变量所指向的地址是相同的,因而(1)处的运行结果为true,又因为s1.equals(s2)是比较s1和s2所指向的对象的内容是否相等,而我们知道这两个对象的内容都是字符串常量”123”,故标记(2)处的运行结果是true。 
用同样的方法分析,s1和s3所指向的对象不一样,内容也不一样,故标记(3)和(4)处运行结果是false。 
再看看s4和s5,这两个引用变量所指向的对象的内容都是一样的(内容都是123),但是这两个对象是用new操作符创建处类的,是在内存中分配两块空间给这两个对象的,因而这两个对象的内存地址不一样,故事两个不同的对象,标记(5)处的s4 == s5 运行结果为false,但是内容一样,故标记(6)处的s4.equals(s5)运行结果为true。同理,s4和s6所指向的对象地址不同,内容也不相同。故标记(7)(8)处运行结果为false。 
s1和s4分别指向两个不同的对象(之所以这样称呼,是因为这两个对象在内存中的地址不相同,故而对象不相同),故标记为(9)处的s1 == s4运行结果为false,而标记为(10)处的s1.equals(s4)运行结果疑问:乍一看结果,有点惊讶,为什么不是true呢,不是说equals方法是比较内容的吗? 
解释:不错,如果在新类中被覆盖了equals方法,就可以用来比较内容的。但是在上面的例子中类Value并没有覆盖Object中的equals方法,而是继承了该方法,因此它就是被用来比较地址的,又v1和v2的所指向的对象不相同,故标记(1)处的v1.equals(v2)运行结果为false,标记为(2)处的v1 == v2运行结果也为false。 



自己总结一下: 

1.equal 

           对于object类(或继承object类,但无实现自定义equal),是比较对象的类型的,除非同一对象,都不相等。 

            对于基本类型(如int)不能使用equal。 

          对于基本类型的封装类,equal是比较其类型 

           对于继承object类的,又实现了自定义equal(重写其equal),则是按自定义的equal执行,一般重写的就是重写成对其内容进行比较。一般api中继承object的类都已重写equal对内容进行比较。 

    int a = 3; 

   Integer d=3; 

   System.out.println(d.equals(a));    //true,因为其内容是相等的 
   System.out.println(a.equals(d));   //报错,因为基本类型int a没有equal这个方法 



2,== 

“==”比较两个变量本身的值,即两个对象在内存中的首地址。 


二次总结 
  1.“==”比较两个变量本身的值,即两个对象在内存中的首地址。 
    “equals()”比较字符串中所包含的内容是否相同。(StringBuffer 和StringBuilder特殊,==和equal都是比较地址) 


StringBuilder ww = new StringBuilder("111"); 

StringBuilder qq = new StringBuilder("111"); 

System.out.println(ww == qq); // false 
System.out.println(ww.equals(qq))  // false 

2.基本数据类型:boolean、char、byte、shot、int、long、float、double等没有equal方法 

3.对于String ,基本类型的包装类型Boolean、Character、Byte、Shot、Integer、Long、Float、Double,适用1即==表比较地址,equal表示比较内容 




转载来自http://blog.youkuaiyun.com/qq_32709845/article/details/52852796

http://www.cnblogs.com/shenliang123/archive/2012/04/16/2452156.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值