1)String
String是Java中的字符串类,属于引用数据类型。所以String的对象存放的是引用的地址。在底层是一个字符型数组。
String是不可变的。所谓的不可变是指一个对象有了一个引用过后它的引用不可变,每次对String对象增加字符串,该对象的引用将会指向一个新的引用地址。
在方法区有一个常量池,当字节码加载如虚拟机时字符串常量就已经加载进常量池并给它分配一个内存地址。字符串对象就引用该地址。
=========================================
String str = "abc";
str = str + "d";//引用地址将会改变,这时的str是一个新的对象。
===========================================
2)String对象创建分析
public class Test {
public static void main(String[] args) {
//str1存放(引用)常量池中的地址
String str1 = "abcd";
//str2存放(引用)堆中对象的地址,而堆中的数据存放的是常量池中的地址,多重引用
String str2 = new String("abcd");
}
}
如果常量区中有该字符串,就不重新存储,而是直接引用,这样节省了内存。该程序只在堆中开辟了一个空间。
3)Java对String的优化
源代码:
public class Test {
//返回一个cd字符串
public static String getString() {
return "cd";
}
public static void main(String[] args) {
String str1 = "abcd";
String str2 = "a" + "b" + "c" + "d";
String str3 = "ab" + "cd";
String temp = "ab";
String str4 = "ab" + temp;
String str5 = "ab" + getString();//调用上面定义的方法得到cd
//注意:这里的‘==’比较的是它们的引用地址,而不是比较的它们的值
System.out.println(str1 == str2);//结果为true
System.out.println(str1 == str3);//结果为true
System.out.println(str1 == str4);//结果为false
System.out.println(str1 == str5);//结果为false
}
}
==========================================
使用反编译工具将上面字节反编译得到的代码:
public class Test{
public static String getString() {
return "cd";
}
public static void main(String[] args) {
String str1 = "abcd";
String str2 = "abcd";
String str3 = "abcd";
String temp = "ab";
String str4 = "ab" + temp;
String str5 = "ab" + getString();
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str1 == str4);
System.out.println(str1 == str5);
}
}
==============================================
结论:
我们对加红的代码进行比较,也就是Java虚拟机对String经行了优化,这里str1、str2、str3引用了同一个地址,共用了常量区中的数据,所以它们的引用地址进行比较结果是相同的。但是变量和方法无法确认它们准确的值只有运行到该行代码时才能却定,在堆中新创建一个空间。所以str1、str4、str5引用地址的比较不相等。
Java虚拟机的优化共用了资源,减少了内存的使用,从而释放了更多的空间。