`
中南大宝
  • 浏览: 33685 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

equals和==的区别

阅读更多

        这两天一直在看数据结构和算法,看到一些内容就想起了龙哥曾经讲过的“equals”和“==”的区别,于是重新回顾梳理了一遍,更加深了印象。现在做一下比较:

 

要辨别“equals”和“==,首先必须明白两个概念“值传递”和“引用传递”。

 

简单来说,“值传递”就是当你创建一个对象的时候(注意啊:int一个整型也是创建对象),JVM在内存中给你的这个对象开辟了一块地址;“引用传递”就是不重新分配内存资源,只是把你新声明(注意是声明啊,并没有实例化一个对象)的对象指向了一个已经在内存中有的对象,即两个对象名同指一处地址,当然我更改这个对象的值后,两个对象名所指向的这个对象的值都变了。

(ps:这个地方被大神指出有误,部分地方博主进行了更改,划掉的区域是被指出有误的地方,为避免难以看懂评论,特作此处理。博主另写了一篇博文对内存分配中的"栈"与"堆"进行了分析)

 

这里还要强调一下“new”,这是实例化对象的标识,也就是在内存中重新分配空间的标识。(关键字new为每个对象申请内存空间,除基本类型,且所有的对象都在堆heap中分配空间)我们通常用的时候,例如比较字符串,“equals”比较的是这两个字符串的值是不是一样,而“==”则比较的是这两个字符串的引用地址是否一样。例如下面的代码示例:

/**
 * 字符串中“equals”和“==”对比示例 
 * @author 赵广超
 */
public class equalsTest {
	public static void main(String[] args) {

		String aaa =new String("abc");
		String bbb =new String("abc");
		String ccc ="abc";
		String ddd=aaa;
		
		if(aaa == bbb){
			System.out.println("aaa == bbb");
		}else{
			System.out.println("aaa  != bbb");
		}
		if(aaa.equals(bbb)){
			System.out.println("aaa equals bbb ");
		}else{
			System.out.println("aaa not equals bbb ");
		}
		if(aaa == ccc){
			System.out.println("aaa == ccc");
		}else{
			System.out.println("aaa  != ccc");
		}
		if(aaa.equals(ccc)){
			System.out.println("aaa equals ccc ");
		}else{
			System.out.println("aaa not equals ccc ");
		}
		if(bbb == ccc){
			System.out.println("bbb == ccc");
		}else{
			System.out.println("bbb  != ccc");
		}
		if(bbb.equals(ccc)){
			System.out.println("bbb equals ccc ");
		}else{
			System.out.println("bbb not equals ccc ");
		}
		if(aaa == ddd){
			System.out.println("aaa == ddd");
		}else{
			System.out.println("aaa  != ddd");
		}
		if(aaa.equals(ddd)){
			System.out.println("aaa equals ddd ");
		}else{
			System.out.println("aaa not equals ddd ");
		}
		if(bbb == ddd){
			System.out.println("bbb == ddd");
		}else{
			System.out.println("bbb  != ddd");
		}
		if(bbb.equals(ddd)){
			System.out.println("bbb equals ddd ");
		}else{
			System.out.println("bbb not equals ddd ");
		}
		if(ccc == ddd){
			System.out.println("ccc == ddd");
		}else{
			System.out.println("ccc  != ddd");
		}
		if(ccc.equals(ddd)){
			System.out.println("ccc equals ddd ");
		}else{
			System.out.println("ccc not equals ddd ");
		}
	}
}

 

结果如下:

        aaa  != bbb 

        aaa equals bbb  

        aaa  != ccc 

        aaa equals ccc  

        bbb  != ccc 

        bbb equals ccc  

        aaa == ddd 

        aaa equals ddd  

        bbb  != ddd 

        bbb equals ddd  

        ccc  != ddd 

        ccc equals ddd  

 

 

对上面的结果我们可以做如下解释:

 

String aaa =new String("abc");

        String bbb =new String("abc");

        String ccc ="abc";

        String ddd=aaa;

 

       左边的代码在内存中分配的结果如右边所示:故有控制台的打印信息 即“equals“比较的是两个值是不是一样,而”==“比较的是内存地址是不是相同。

    可是,实际的并不总是这样的。String类中的Equals这个方法重写了超类Object(Object类被所有的其他类继承)中的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方法时,可能会有不一样的效果。这就提醒我们在编写自己的类时,如果要比较的话,要注意重写Object类中的equals方法。

 

——2013.1.3写于新校区图书馆

 

 强烈建议转至痴情研究java内存中的对象一文进行深入探究

 

  • 大小: 16.2 KB
6
5
分享到:
评论
18 楼 中南大宝 2013-10-04  
逸情公子 写道

之前试着看了两三次,每次都看一半就看不下去了,大四了事情少了很多才能够静下心来好好的看完这篇文章,收获蛮大的,自动装箱机制,string stringbuffer 和 stringbuilder等等,让我更深的了解了java内存的相关知识,谢谢学长!超佩服你钻研的劲头!!
17 楼 逸情公子 2013-02-06  
16 楼 xsgkaka 2013-01-31  
看来还要努力加强基础知识啊
15 楼 kidneyball 2013-01-30  
caizi12 写道

对,说的是这段。这句说的就比较确切:“传递对象引用的值”,也更让人容易理解,有时候英文翻译到中文确实会有些偏差,特别是这种比较容易混淆又可有多种解释的词,“引用传递”这个说法我想平常很多人还是会这样说的,而大家也知道针对的是对象变量。


“传递对象引用的值”还是“值传递”呀,只不过这个“值”是一个“引用”而已。在Java里没有必要专门弄出来一个“引用传递”的概念。所谓“按值传递(pass by value)”和“按引用传递”(pass by reference)的主体是变量本身,而不是变量所指向的类型。例如在C++中使用按引用传递,你可以:



变量a“按引用传递”给b后,修改b就直接修改了a,在java中根本就没有这种特性。
14 楼 caizi12 2013-01-30  
kidneyball 写道
caizi12 写道
jayming 写道
kidneyball 写道
概念完全乱套了

1. java里没有“引用传递”的说法,所有传递都是“值传递”。C中的引用传递可以通过修改形式参数直接更改对应传入的实际参数值,在Java中根本做不到。你把一个对象变量传入到一个方法中,在方法内不可能改变这个变量本身的值,最多只能更改这个变量所指向的对象中的属性而已。

2. java里的数据类型分为基本类型(primative type)和引用类型(reference type)。java里没有指针的概念,所有引用都是通过对象实现的,都对应一个对象ID。==判断“值相等”,可以用在任何类型的值上,而引用类型的值就是对象ID。equals是Object对象上的一个方法,用来判断“自然序(natural order)相等”。equals方法在Object上的默认实现就是直接用==来判断,但每个具体子类都可以覆盖这个方法,实现符合其实际语义的自然序相等判断。

楼主应该好好参透参透这位同学的精彩解说


精彩吗?谈不上,第一句话就错了。Sun 公司在某种程度上也支持这一见
解(详见think in java 351页,该书多此使用该词)。你这么肯定不知道从何而来呢?


你指这段吗?
引用

对于“按值传递”的含义,目前存在两种存在明显区别的见解:

(1) Java 按值传递任何东西。若将基本数据类型传递进入一个方法,会明确得到基本数据类型的一个副本。 但若将一个句柄传递进入方法,得到的是句柄的副本。所以人们认为“一切”都按值传递。当然,这种说法 也有一个前提:句柄肯定也会被传递。但 Java 的设计方案似乎有些超前,允许我们忽略(大多数时候)自己处理的是一个句柄。也就是说,它允许我们将句柄假想成“对象”,因为在发出方法调用时,系统会自动照管两者间的差异。

(2) Java 主要按值传递(无自变量),但对象却是按引用传递的。得到这个结论的前提是句柄只是对象的一 个“别名”,所以不考虑传递句柄的问题,而是直接指出“我准备传递对象”。由于将其传递进入一个方法 时没有获得对象的一个本地副本,所以对象显然不是按值传递的。Sun 公司似乎在某种程度上支持这一见解,因为它“保留但未实现”的关键字之一便是 byvalue(按值)。但没人知道那个关键字什么时候可以发挥作用。

首先从这段话本身来看,我倾向于支持第一种观点。这是java实际的实现方式。而第二点纯属作者的一种推断和在高层的一种概念类比,在java语言规范里没有出现过“pass by reference”的字眼(连“句柄”这个提法都没有)。

还有一件很离奇的事,在网上找到的《Java编程思想第4版》中文版和《Thinking in Java forth Edition》英文版的目录结构有很大不同,而在中文版中这段话所在的章节在英文版中根本就没有。反而在英文版中《Everything Is an Object》的《You manipulate objects with references》一节中有如下脚注
引用

正文:
Although you treat everything as an object, the identifier you manipulate is actually a “reference” to an object.1

脚注:
1 This can be a flashpoint. There are those who say, “Clearly, it’s a pointer,” but this presumes an underlying implementation. Also, Java references are much more akin to C++ references than to pointers in their syntax. In the 1st edition of this book, I chose to invent a new term, “handle,” because C++ references and Java references have some important differences. I was coming out of C++ and did not want to confuse the C++ programmers whom I assumed would be the largest audience for Java. In the 2nd edition, I decided that “reference” was the more commonly used term, and that anyone changing from C++ would have a lot more to cope with than the terminology of references, so they might as well jump in with both feet. However, there are people who disagree even with the term “reference.” I read in one book where it was “completely wrong to say that Java supports pass by reference,” because Java object identifiers (according to that author) are actually “object references.” And (he goes on) everything is actually pass by value. So you’re not passing by reference, you’re “passing an object reference by value.” One could argue for the precision of such convoluted explanations, but I think my approach simplifies the understanding of the concept without hurting anything (well, the language lawyers may claim that I’m lying to you, but I’ll say that I’m providing an appropriate abstraction).

大意是说,作者是从C++转型过来的,因此在本书的早期版本使用了C++的句柄,引用传递等字眼,以方便C++程序员理解。后来他读到一本书指出java中根本没有真正的“引用传递”,只有“传递对象引用的值”。最后,他仍然认为自己原来的观点虽然好像有欺骗嫌疑,不过在更高的抽象层面上,更容易理解。

不过,在这个版本中,除了这一段外,搜不到任何“pass by reference”的说法了。



对,说的是这段。这句说的就比较确切:“传递对象引用的值”,也更让人容易理解,有时候英文翻译到中文确实会有些偏差,特别是这种比较容易混淆又可有多种解释的词,“引用传递”这个说法我想平常很多人还是会这样说的,而大家也知道针对的是对象变量。
13 楼 kidneyball 2013-01-30  
caizi12 写道
jayming 写道
kidneyball 写道
概念完全乱套了

1. java里没有“引用传递”的说法,所有传递都是“值传递”。C中的引用传递可以通过修改形式参数直接更改对应传入的实际参数值,在Java中根本做不到。你把一个对象变量传入到一个方法中,在方法内不可能改变这个变量本身的值,最多只能更改这个变量所指向的对象中的属性而已。

2. java里的数据类型分为基本类型(primative type)和引用类型(reference type)。java里没有指针的概念,所有引用都是通过对象实现的,都对应一个对象ID。==判断“值相等”,可以用在任何类型的值上,而引用类型的值就是对象ID。equals是Object对象上的一个方法,用来判断“自然序(natural order)相等”。equals方法在Object上的默认实现就是直接用==来判断,但每个具体子类都可以覆盖这个方法,实现符合其实际语义的自然序相等判断。

楼主应该好好参透参透这位同学的精彩解说


精彩吗?谈不上,第一句话就错了。Sun 公司在某种程度上也支持这一见
解(详见think in java 351页,该书多此使用该词)。你这么肯定不知道从何而来呢?


你指这段吗?
引用

对于“按值传递”的含义,目前存在两种存在明显区别的见解:

(1) Java 按值传递任何东西。若将基本数据类型传递进入一个方法,会明确得到基本数据类型的一个副本。 但若将一个句柄传递进入方法,得到的是句柄的副本。所以人们认为“一切”都按值传递。当然,这种说法 也有一个前提:句柄肯定也会被传递。但 Java 的设计方案似乎有些超前,允许我们忽略(大多数时候)自己处理的是一个句柄。也就是说,它允许我们将句柄假想成“对象”,因为在发出方法调用时,系统会自动照管两者间的差异。

(2) Java 主要按值传递(无自变量),但对象却是按引用传递的。得到这个结论的前提是句柄只是对象的一 个“别名”,所以不考虑传递句柄的问题,而是直接指出“我准备传递对象”。由于将其传递进入一个方法 时没有获得对象的一个本地副本,所以对象显然不是按值传递的。Sun 公司似乎在某种程度上支持这一见解,因为它“保留但未实现”的关键字之一便是 byvalue(按值)。但没人知道那个关键字什么时候可以发挥作用。

首先从这段话本身来看,我倾向于支持第一种观点。这是java实际的实现方式。而第二点纯属作者的一种推断和在高层的一种概念类比,在java语言规范里没有出现过“pass by reference”的字眼(连“句柄”这个提法都没有)。

还有一件很离奇的事,在网上找到的《Java编程思想第4版》中文版和《Thinking in Java forth Edition》英文版的目录结构有很大不同,而在中文版中这段话所在的章节在英文版中根本就没有。反而在英文版中《Everything Is an Object》的《You manipulate objects with references》一节中有如下脚注
引用

正文:
Although you treat everything as an object, the identifier you manipulate is actually a “reference” to an object.1

脚注:
1 This can be a flashpoint. There are those who say, “Clearly, it’s a pointer,” but this presumes an underlying implementation. Also, Java references are much more akin to C++ references than to pointers in their syntax. In the 1st edition of this book, I chose to invent a new term, “handle,” because C++ references and Java references have some important differences. I was coming out of C++ and did not want to confuse the C++ programmers whom I assumed would be the largest audience for Java. In the 2nd edition, I decided that “reference” was the more commonly used term, and that anyone changing from C++ would have a lot more to cope with than the terminology of references, so they might as well jump in with both feet. However, there are people who disagree even with the term “reference.” I read in one book where it was “completely wrong to say that Java supports pass by reference,” because Java object identifiers (according to that author) are actually “object references.” And (he goes on) everything is actually pass by value. So you’re not passing by reference, you’re “passing an object reference by value.” One could argue for the precision of such convoluted explanations, but I think my approach simplifies the understanding of the concept without hurting anything (well, the language lawyers may claim that I’m lying to you, but I’ll say that I’m providing an appropriate abstraction).

大意是说,作者是从C++转型过来的,因此在本书的早期版本使用了C++的句柄,引用传递等字眼,以方便C++程序员理解。后来他读到一本书指出java中根本没有真正的“引用传递”,只有“传递对象引用的值”。最后,他仍然认为自己原来的观点虽然好像有欺骗嫌疑,不过在更高的抽象层面上,更容易理解。

不过,在这个版本中,除了这一段外,搜不到任何“pass by reference”的说法了。
12 楼 caizi12 2013-01-30  
jayming 写道
kidneyball 写道
概念完全乱套了

1. java里没有“引用传递”的说法,所有传递都是“值传递”。C中的引用传递可以通过修改形式参数直接更改对应传入的实际参数值,在Java中根本做不到。你把一个对象变量传入到一个方法中,在方法内不可能改变这个变量本身的值,最多只能更改这个变量所指向的对象中的属性而已。

2. java里的数据类型分为基本类型(primative type)和引用类型(reference type)。java里没有指针的概念,所有引用都是通过对象实现的,都对应一个对象ID。==判断“值相等”,可以用在任何类型的值上,而引用类型的值就是对象ID。equals是Object对象上的一个方法,用来判断“自然序(natural order)相等”。equals方法在Object上的默认实现就是直接用==来判断,但每个具体子类都可以覆盖这个方法,实现符合其实际语义的自然序相等判断。

楼主应该好好参透参透这位同学的精彩解说


精彩吗?谈不上,第一句话就错了。Sun 公司在某种程度上也支持这一见
解(详见think in java 351页,该书多此使用该词)。你这么肯定不知道从何而来呢?
11 楼 jcs130 2013-01-29  
kidneyball 写道
概念完全乱套了

1. java里没有“引用传递”的说法,所有传递都是“值传递”。C中的引用传递可以通过修改形式参数直接更改对应传入的实际参数值,在Java中根本做不到。你把一个对象变量传入到一个方法中,在方法内不可能改变这个变量本身的值,最多只能更改这个变量所指向的对象中的属性而已。

2. java里的数据类型分为基本类型(primative type)和引用类型(reference type)。java里没有指针的概念,所有引用都是通过对象实现的,都对应一个对象ID。==判断“值相等”,可以用在任何类型的值上,而引用类型的值就是对象ID。equals是Object对象上的一个方法,用来判断“自然序(natural order)相等”。equals方法在Object上的默认实现就是直接用==来判断,但每个具体子类都可以覆盖这个方法,实现符合其实际语义的自然序相等判断。

受教了~~
10 楼 wawxy2009 2013-01-29  
看了之后有帮助,尤其是看了评论之后
9 楼 lvwenwen 2013-01-29  
int不是对象
8 楼 songbgi 2013-01-29  

javaeye大牛多 言多必失
7 楼 jayming 2013-01-29  
kidneyball 写道
概念完全乱套了

1. java里没有“引用传递”的说法,所有传递都是“值传递”。C中的引用传递可以通过修改形式参数直接更改对应传入的实际参数值,在Java中根本做不到。你把一个对象变量传入到一个方法中,在方法内不可能改变这个变量本身的值,最多只能更改这个变量所指向的对象中的属性而已。

2. java里的数据类型分为基本类型(primative type)和引用类型(reference type)。java里没有指针的概念,所有引用都是通过对象实现的,都对应一个对象ID。==判断“值相等”,可以用在任何类型的值上,而引用类型的值就是对象ID。equals是Object对象上的一个方法,用来判断“自然序(natural order)相等”。equals方法在Object上的默认实现就是直接用==来判断,但每个具体子类都可以覆盖这个方法,实现符合其实际语义的自然序相等判断。

楼主应该好好参透参透这位同学的精彩解说
6 楼 BuN_Ny 2013-01-29  
1. 新手帖
2. 月经帖
3. 很多错误
5 楼 kidneyball 2013-01-29  
概念完全乱套了

1. java里没有“引用传递”的说法,所有传递都是“值传递”。C中的引用传递可以通过修改形式参数直接更改对应传入的实际参数值,在Java中根本做不到。你把一个对象变量传入到一个方法中,在方法内不可能改变这个变量本身的值,最多只能更改这个变量所指向的对象中的属性而已。

2. java里的数据类型分为基本类型(primative type)和引用类型(reference type)。java里没有指针的概念,所有引用都是通过对象实现的,都对应一个对象ID。==判断“值相等”,可以用在任何类型的值上,而引用类型的值就是对象ID。equals是Object对象上的一个方法,用来判断“自然序(natural order)相等”。equals方法在Object上的默认实现就是直接用==来判断,但每个具体子类都可以覆盖这个方法,实现符合其实际语义的自然序相等判断。
4 楼 enson16855 2013-01-28  
不多说,哥们!看了你的文章,感觉你还有很多路要走。有时间多研究一下java基础和java源码吧!java其实是一门优雅的预言!
3 楼 在世界的中心呼喚愛 2013-01-28  
差不多,意思达到。。。
2 楼 alvin198761 2013-01-28  
写文章是件好事,但是我建议你先了解一下java基础,然后看看源码,再写,因为你写的很多东西都是错的,你叫看的人情何以堪,我随便看了几下,就有一堆问题。
比如:“(int一个整型也是创建对象),操作系统在内存中给你的这个新对象重新分配了一个地址”这句话至少存在两个问题,1.int类型不是对象吧,2.就算是对象,int类型也不一定会重新分配内存,如果你看过源码就会知道,我不多做解释。
在比如:“这里还要强调一下“new”,这是实例化对象的标识,也就是在内存中重新分配空间的标识。”这句话是你定义的吧,事实是这样的吗?
还是那句话,写文章是好事,多看看源码吧!
1 楼 zhukewen_java 2013-01-28  
int不是对象

相关推荐

Global site tag (gtag.js) - Google Analytics