1. 程式人生 > >論 java中String 和 new String還有物件中的String字串在記憶體中的儲存

論 java中String 和 new String還有物件中的String字串在記憶體中的儲存

一直以來,所有人都說,java中的String型別是不可變的,可是為什麼不可變確很少有人說的透徹,String和new

String的區別,物件中的String和直接定義一個String是否有區別,一直都是一知半解。看了很多文件都是各種猜測,沒有具體程式碼來證明。今天看了上面的部落格做了一些測試,有一些心得。String型別一直是一個特殊的資料型別,在建立的時候就是不可變的,會在Stringconstant pool中建立一個常量,當我們再次建立一個字串的時候,jvm會先去String constant pool 中檢索這個這個常量是否存在,如果存在則將引用返回,如果不存在,則建立新的常量,然後將引用返回。那麼使用new String的方法建立?或者是在一個物件的例項中建立一個字串?記憶體中這個值會如何儲存?是在Heap中直接開闢空間儲存,還是會在Stringconstant pool 中建立,然後在Heap中建立一個引用?接下來,通過程式碼來證明,在記憶體中String究竟是如何儲存的

首先是String和new String的區別

public static void main(String[] args) throws Exception { String hello=“hello world”; String xx=new String(“hello world”); String yy=“hello world”;

//輸出判斷記憶體地址是否相等
System.out.println("xx==hello : "+ (xx==hello));
System.out.println("yy==hello : "+ (yy==hello)+"\n");

//通過反射修改hello的value值
Field hello_field=String.class.getDeclaredField("value");
hello_field.setAccessible(true);
char[] value=(char[])hello_field.get(hello);
value[5]='_';

//首先輸出修改結果
System.out.println("Hello: "+hello+"\n");

//然後判斷記憶體地址是否有變化
System.out.println("xx==hello : "+ (xx==hello));
System.out.println("yy==hello:"+(hello==yy));
System.out.println("xx==yy:"+(xx==yy)+"\n"); 

//最後輸出所有值的結果
System.out.println("xx: "+xx);
System.out.println("yy: "+yy);
System.out.println("Hello: "+hello);

} 程式碼執行結果

 xx==hello : false
yy==hello : true
 
Hello: hello_world
 
xx==hello : false
yy==hello:true
xx==yy:false
 
xx: hello_world
yy: hello_world
Hello: hello_world

根據結果可以判斷,無論是String還是new String最終都指向了String constant pool中,只不過是String直接指向了Stringconstant pool中。而new String是在Heap中建立了一個指向String constant pool中的引用。那麼,物件中String是否也是這樣的?那麼我們是否可以這樣推測,在java中所有的String型別的字串,最終都會指向Stringconstant pool 中? 然後是String和Object的區別

import java.lang.reflect.Field;

public class StringTest {

public String name="hello world"; 

public String phone; 

public StringTest(String phone) {
	// TODO Auto-generated constructor stub
	this.phone=phone;
}

public static void main(String[] args) throws Exception {
	StringTest a = new StringTest("hello world");
	StringTest b = new StringTest("hello world");
	String c = "hello world";
	String e = new String("hello world");
	
	//首先判斷不同物件中的字串地址是否相等
	System.out.println("a.name==a.phone:"+(a.name==a.phone));
	System.out.println("a.name==b.phone:"+(a.name==b.phone));
	System.out.println("a.name==c:"+(a.name==c));
	System.out.println("e==c:"+(e==c)+"\n");
	
	//然後修改c在記憶體中的值
	Field hello_field=String.class.getDeclaredField("value");
	hello_field.setAccessible(true);
	char[] value=(char[])hello_field.get(c);
	value[5]='_';
	
	//首先判斷不同物件中的字串地址是否相等
	System.out.println("a.name==a.phone:"+(a.name==a.phone));
	System.out.println("a.name==b.phone:"+(a.name==b.phone));
	System.out.println("a.name==c:"+(a.name==c));
	System.out.println("e==c:"+(e==c)+"\n");
	
	//直接輸出值判斷是否發生變化
	System.out.println("a.name: "+a.name);
	System.out.println("b.name: "+b.name);
	System.out.println("a.phone: "+a.phone);
	System.out.println("b.phone: "+b.phone);
	System.out.println("c: "+c);
	System.out.println("e: "+e);
}

} 程式碼執行結果

a.name==a.phone:true
a.name==b.phone:true
a.name==c:true
e==c:false
 
a.name==a.phone:true
a.name==b.phone:true
a.name==c:true
e==c:false
 
a.name: hello_world
b.name: hello_world
a.phone: hello_world
b.phone: hello_world
c: hello_world
e: hello_world

根據執行結果可以看出,不同物件中的String值相等時,其指向的是同一個String constant pool中的地址,如果我們修改了其中一個值得時候,所有的引用都會發生改變,而且其記憶體地址的比較並沒有發生變化。所以我們的推測應該是正確的,因時間關係,沒有了測試陣列和其他的關於String型別的字串是否也是如此,不過根據上面的結果,我們應該可以大膽猜測,java中,如果定義了String型別的字串,最終的都存在String constant pool 中。如果有什麼意見或建議請在下方留言,再次感謝原博主