JAVA数据类型比较==与equals浅析
引言
我们知道,String在JAVA中不是作为基本数据类型而存在的,它是一种被封装的类。而在比较两个字符串是否相等的时候,我们需要使用其自带方法equals。可是在这里为什么我们不能使用==呢?
我们先看一段代码
String str1="Hello";
String str2=new String("Hello");
String str3="Hello";
System.out.print("str1==str2:");
System.out.println(str1==str2);
System.out.print("str1==str3:");
System.out.println(str1==str3);
System.out.print("str2==str3:");
System.out.println(str2==str3);
此时输出,将会得到
str1==str2:false
str1==str3:true
str2==str3:false
这就会引出我们接下来的话题,JAVA中对不同数据类型的比较方式。
基于数据类型的==比较符
对于上面的实例最简单的一种解释方式是这样的,JAVA中==比较符号比较的是两个对象是否指向一个内存地址,即两个对象是否为一个引用(因为JAVA避讳指针这一说法,故不采用C语言的解释方法)。
对于str1与str3,我们是直接将字符串面量赋予给它,所以它们此时指向的是内存中的同一个地方,是一样的引用。所以==判断将会返回true,而str2采用new操作告诉了编译器用户想要的是一个全新的字符串,此时它会开辟另一块内存,导致与str1与str2非同一个引用,==返回false。
那么对于基本数据类型又是否如此呢?我们对于简单的例子:
int a=1;
int b=1;
a==b;
此时采用引用的解释方式也仍然行得通,因为JVM会缓存JAVA中基本数据类型的常量值,所以a与b此时的确指向一个引用。
但是如果碰到这样的情况:
int a=3;
double b=3.0;
System.out.println(a==b);
显然此时a b所指向的并不是同一个引用,但是返回的结果是true。所以JAVA中的==符号的比较方式根据数据类型的不同将会发生变化,其特点是:
1.当操作数为基本数据类型时,编译时将会生成if_icmpne指令,此时比较的是内存中的数据是否相等
2.当操作数为对象时,编译器会生成if_acmpne指令,其比较的是两者是否为同一个引用。
使用equals
为了防止不能比较两个对象的情况出现,一般来说数据类型的对象一般都会提供equals这一方法。而equals的底部实现仍然是调用==运算符进行数据的比较,以实现对比两个对象是否相等。
以下是String的equals实现:
在本文开始所给出的例子中,可能会让人产生一种错觉,就是如果两个对象是由赋值符号=所构建的话,那么==的比较将会总是返回true。但是这却也并不是总是正确的。例如以下这个例子:
Integer a=127;
Integer b=127;
System.out.println(a==b);
Integer c=129;
Integer d=129;
System.out.println(c==d);
此时返回的结果是:true和false。这种情况的出现是由于JVM会对Integer类型的 -128~127 的常量值进行缓存,所以当数据范围超过时将会自动new一个新的。但是这个例子换成int的话却会在值相等时总是返回true。
总结
JAVA不像C#一样真正的万物皆对象,实际上有一些trick。从本质上来说这一切都是由JVM决定的,而我们需要记住的就只是:使用==比较基本数据类型,而使用equals比较对象,并且遵循这一法则记得实现自己的equals。