最近在通过阅读《深入理解Java虚拟机——JVM特性与最佳实践》这本书时,发现书中在介绍运行时常量池中有这样一段话:
“运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多得是String类的intern()方法”
intern()方法在jdk的文档中是这样描述的:“When the intern method is invoked, if the pool already contains a string equal to this {@code String} object as determined by the {@link #equals(Object)} method, then the string from the pool is returned. Otherwise, this {@code String} object is added to the pool and a reference to this {@code String} object is returned.”简而言之,如果池中有该变量即引用,没有就创建。
在验证之前,要了解一下“==” 和 equals方法的区别:
Java有八大基础类型分别是:byte, short, char, int, long, float, double, boolean
上述数据类型没有equals方法,==方法就是比较数据的值是否相等
而对于其他复合数据类型而言,==方法是比较两个对象的引用是否相等,也就是比较两个对象的地址是否相等(是不是同一个对象),众所周知所有java类型都有个公共的爹,Object类,而在该类中也定义了一个equals方法
public boolean equals(Object obj) {
return (this == obj);
}
可以看到该方法就是调用了==方法即比较两个对象的地址值是否相等,String类中对该类进行了重写,
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
在该方法中,首先判断是否为同一个对象,如果不是同一个对象,那么判断是否为String类型,如果不为String类型就返回false,如果为String类型将其转换为基本数据类型char,通过基本数据类型的比较为值比较来比较两个String对象的值是否相等。
下面的代码可以验证:
String str0 = new String("a");
String str1 = str0.intern();
String str2 = "a";
String str3 = "a";
System.out.println(str1 == str0);//false
System.out.println(str2 == str0);//false
System.out.println(str2 == str1);//true
System.out.println(str3 == str2);//true
以上对象的比较如果通过equals方法返回值都为true