兩種情況:如果是基本數據類型,被final修飾的變量一旦初始化就不能改變;如果是引用數據類型的變量,初始化之后不能指向另外一個對象。
基本數據類型:
package cn.yqg.day2; public class StringTest { public static void main(String[] args) { final int a; int b=234; a=b; System.out.println(a); } }
我們看到上面的代碼a是final類型的,但是沒有被初始化,所以可以給a賦值。如果a被初始化,a存儲的值就不能改變了,示例如下。
package cn.yqg.day2; public class StringTest { public static void main(String[] args) { final int a=123; int b=234; a=b;//編譯通不過,會報錯建議去掉fianl System.out.println(a); } }
如果是引用數據類型
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
package cn.yqg.day2; public class StringTest { public static void main(String[] args) { final StringBuffer a=new StringBuffer("ppp"); System.out.println(a); System.out.println(a.hashCode()); a.append("kkk"); System.out.println(a); System.out.println(a.hashCode()); } }
運行結果:
ppp 2018699554 pppkkk 2018699554
我們發現變量內容變了,引用沒變。
我們把String定義為final類型,那么String類不能被繼承,開始創建對象ppp,並用指向ppp的存儲地址,后來a=a+“kkk”會新創建一個內存來存儲該對象,並把新的地址賦值給a,那么老的存儲ppp對象的地址就沒有變量賦值了,就會成為垃圾。
String a="ppp"; a=a+"kkk";
我們看到a的對象內容改變了
不允許String類的引用地址被改變是為了安全性着想,我們看這個例子。
package cn.yqg.day3; public class Test2 { public static void main(String[] args) { String a=new String("fds"); String b=new String("ddd"); String c=b;//c和b都指向ddd對象 c=c+"ds";//c會創建新的內存,內存中存儲新的對象,這是ddd只有b指着,c指向新對象。 System.out.println(b); System.out.println(c); } }
運行內存圖:

運行結果:
ddd
dddds
我們從此可以知道,c新開辟一個地址並進行存貯,這就保證了String類的安全性,相反StringBuilder就存在安全隱患
package cn.yqg.day3; public class Test2 { public static void main(String[] args) { StringBuilder s=new StringBuilder("ppp"); StringBuilder r=s; r.append("kkk"); System.out.println(r); System.out.println(s); } }
運行結果:
pppkkk
pppkkk
r改變會導致s也改變,因為他們指向得內存地址一樣。
------------------------------------------------------------------------------------------------------------------------------------------------------
