JCF之equals与==分析

学习了Hash容器之后,让我们来深入分析一下Java中的equals与==操作。

==操作对于基本数据类型变量比较的是两个变量的值,对于引用型变量比较的是两个变量所指向的堆中内容的地址,即栈中的内容

对于equals,先来看看Object中的equals方法定义

/*
equals 比较非空对象引用
自反性,x.equals(x)返回true
对称性:x.equals(y)与y.equals(x)结果相同
传递性:如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)返回true
一致性:多次执行x.equals(y)的结果相同
对于任何非空引用x,x.equals(null)返回false;
*/
public boolean equals(Object obj) {
	return (this == obj);
}

从这个定义中可以看出:equals的默认操作表示两个变量是否是对同一个对象的引用,或者说是比较所指之对象的内存地址是否相同

我们经常会这样使用:

String s1 =new String("hello");
String s2 =new String("hello");
System.out.println(s1.equals(s2));//结果为true

虽然s1s2是两个不同对象的引用(即它们指向内存中不同的空间),但返回的结果却是true,

这是因为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++])//逐个比较两个string中的字符
			return false;
		}
		return true;
	    }
	}
	return false;
}

if (this == anObject) {

    return true;

}

这段代码判断转型的情况,比如下面这样的情况:

String s = "hello";
Object o = (Object) s;
System.out.println(s.equals(o));//true

anObject instanceof String

这句判断传入的引用是否指向一个String对象。

如果是,则通过比较每个字符来判断,遇到不相等的字符,则返回false

个人认为,可以先判断两个字符串的长度,如果长度不等,则返回false,因为如果两个很长的字符串只有最后一个字符不相同,

那么需要比较到最后一个字符才能知道结果,这样,不好!不好!

分析这个方法的目的在于说明我们可以通过重写equals方法来自定义equals的实现,默认情况是比较对象的地址,

我们可以像String那样重写为比较对象的内容,或者别的。

我们甚至可以都返回true,这样就和谐了,呵呵!

对于什么时候需要重写equals()方法,《Effective Java》chapter3中有详细描述.

简单数据类型和封装类中的equals==

Java 为每一个简单数据类型提供了一个封装类,每个基本数据类型可以封装成对象类型。
int Integer )和 char Character ),其余类型首字母大写即成封装类类型名。

double (Double), float(Float),long(Long), short(Short),byte(Byte),boolean(Boolean).

intInteger为例说明
JavaintInteger区别如下:
1.int是基本的数据类型,默认值可以为0
2.Integerint的封装类,默认值为null
3.intInteger都可以表示某一个数值;
4.intInteger不能够互用,因为他们是两种不同的数据类型;

来分析下面这些表达式:

int a1 = 1;
int a2 = 1;
Integer b1 = new Integer(1);
Integer b2 = new Integer(1);
System.out.println(a1 == a2);//true
System.out.println(b1 == b2);//false
System.out.println(b1.equals(b2));//true
System.out.println(b1.equals(a1));//true
System.out.println(a1==b1);//true

a1==a2 这个是成立的,必须的!

b1==b2 表达式的值为false,虽然是相同的数据类型,但是它们是两个对象,在堆上占用着不同的空间,==比较的是2个对象的地址,它们的地址是不相等的

b1.equals(b2)==true 这个是成立的,表达式的值为true. 相同数据类型,两个对象,地址不同,内容相同, quals比较的是2个对象的内容,所以成立。

Integer中重写了equals

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
	  return value == ((Integer)obj).intValue();
    }
     return false;
}
 public int intValue() {
	return value;
}

b1.equals(a1),结果为true因为equals比较的是两个对象,所以a,b都不能为基本数据类型,否则会出编译错误。(在jdk1.5以上版本中,由于会对基本数据类型进行自动封装,b1可以为基本数据类型,a1不可以)

a1==b1;结果为true 因为此时Integer对象b1会自动解封。

同理,其它的封装类和基本类型也是这样的情况。

分析一下关于String的特殊情况:

String s1 = "Hello";              // String literal  
String s2 = "Hello";              // String literal  
String s3 = s1;                   // same reference  
String s4 = new String("Hello");  // String object  
String s5 = new String("Hello");  // String object  
System.out.println("s1==s2:"+(s1==s2));
System.out.println("s1==s4:"+(s1==s4));
System.out.println("s3==s4:"+(s3==s4));
System.out.println("s4==s5:"+(s4==s5));

结果为:

s1==s2:true

s1==s4:false

s3==s4:false

s4==s5:false

s4==s5:false

这个结果好理解,s3s4指向内存中的两个不同的对象(虽然对象的内容是相同的)

s1==s3:false

s1==s2:true 

s3==s4:false

这三个结果与String的特殊之处有关。

请看下图:


上图已经一目了然了,s1、s2、s3、s4、s5这五个引用所指对象的内容虽然都为"Hello",但在内存中的位置是不一样的。

s1、s2、s3指向常量池中的"Hello"字符串,而s4、s5指向堆中的两个对象。

java中的常量池技术是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),

则在需要重复重复创建相等变量时节省了很多时间。

常量池其实也就是一个内存空间,不同于使用new关键字创建的对象所在的堆空间。 

java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。

下一篇将深入分析equals()与hashcode()的关系。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值