我在《用反编译研究Java语言细节》这篇文章中作了关于字面值相同字符串常量可以划==的原因作了这样的猜测,原文如下:
java虚拟机并没有定义比较 的字符串指令,就算定义这样的检查会使程序的效率很低。我想这份工作应该交给java编译器。因为java编译器很清楚程序中的字符串常量是否 相同,编译器只要将程序中所有相同的字符串的引用都指向相同的内存地址就可以了。但是程序运行的过程当中内存地址是不固定的,而java编译器 又无法得知程序运行时的状况。那应该如何处理呢?可以用这样一个方法。举一个例子,一个机构要接待陆续来自不同地方由不同学校的学生, 要把同一个学校的学生放在同一间教室。而且不清楚到底有哪些学校。首先接待员接待学生的时候问清楚是哪个学校的,如果是该学校首个到达的学生 要为其指派向导,由向导为负责教室安排。并将学校和向导的信息记录在案。下次如有该学校的学生,就为其指定该向导。同理,java编译器编译的时候 遇到一个常量,如果是新的常量java编译器就为其定义一个指针,并把该常量的引用指向该指针,该指针具体的指向地址由java虚拟机指定。然后将常量记 录下来用作比较。
有一天突然想到了一个方法证明这个猜想,但却证明了这个猜想是错误的 首先定义一个类
public class StringConstant(){ String str = "黑马"; public getString(){ return str; } }
用反射获取字符串
Class clazz = Class.forName("StringConstant类的完全限定名"); Method getStr = clazz.getMethod("getStr"); String s = "黑马"; System.out.println(s == getStr.invoke(clazz.newInstance()));
按照我的推测,编译器是不会对StringConstant类进行检查的,s和str应该不是同一个对象,打印的结果应该是false。但实际的结果却是false。这说明我的猜测是错误的。