已经了解了==与equals的区别,但是==的运行机理会是怎么样呢,看看下面的代码,能不能猜出它运行的结果。
public class Compare{
public static void main(String[] args){
String str1 = "helloworld";
String str2 = "world";
System.out.println(str1 == "helloworld");
System.out.println(Str.str3 == str1);
System.out.println(str1 == "hello"+"world");
System.out.println(str1 == "hello"+str2);
}
}
class Str{
static String str3 = "helloworld";
}
在我第一次看到这段代码的时候,我马上就觉得,它应该是四个false,因为==是比较他们的reference是不是一样,所以即使都是helloworld,也没有一样的reference,所以都应该是false,但是运行了结果之后我发现,除了最后一个是false以外,都是true,和我想的一点都不一样。
Java当中在编译时引进了代码优化的机制,那么我理解的是,它不单是一种代码的优化,还应该是程序的优化,又或者其实设计者本身就是这个意思,只是在翻译的时候,翻译的人只是按照了字面的意思,把这个机制翻译成为了代码优化,而实际上,Java的优化机制,不单单是优化了代码,还优化了程序运行时可占用的内存,也就是说,在编译的时候,按照尽量少的占用内存的原理,去编译它。所以,当在编译的时候,str1,与Str的str3,因为内容都是helloworld,所以编译器为了节省内存,给了他们一块内存地址,所以他们的reference是一样的,至于"hello“+ "world"因为本身就是常量,编译的时候就可以确定的,所以在编译的时候,只有一个内存记下了"helloworld"的内容,之后给了它们相同的reference,只是"hello"+str2,在编译的时候,还不能确定,只有等到runtime的时候,才能确定,所以它的reference就和其他的reference不一样了。现在,运行的结果就很清楚了,应该是
true
true
true
false
以上只是我个人的思考,若是有不对的地方,望指教。
补:最近看了一个SCJP的课程,上面说这个==在1.4之前是不一样的,是到了1.4之后才变成这样的,因为1.4之前没有注意过这个问题,所以不是很清楚。
值得注意的是,关于primitive type使用==是可以比较内容的,因为primitive type的内容是在stack里面的,可以直接比较,没有要比较reference指向的概念,而Object type使用==则需要考虑他们的reference是不是指向同一块heap了。
还有一点需要注意,如果String s是用构造器赋值,也就是String s = new String("xxx"),这时候,再去用==比较,就会得到false,很简单,这里使用了构造器,新实例了对象,两个对象虽然有着相同的值,但是两者并不是一个实例,所以会false。