1. 程式人生 > >在Java中String類為什麽要設計成final?String真的不可變嗎?其他基本類型的包裝類也是不可變的嗎?

在Java中String類為什麽要設計成final?String真的不可變嗎?其他基本類型的包裝類也是不可變的嗎?

數據 pri 創建 long tde 繼承 set 字符串常量 通過

最近突然被問到String為什麽被設計為不可變,當時有點懵,這個問題一直像bug一樣存在,竟然沒有發現,沒有思考到,在此總結一下。

1.String的不可變
String類被final修飾,是不可繼承和修改的。當一個String變量被第二次賦值時,不是在原有內存地址上修改數據,而是在內存中重新開辟一塊內存地址,並指向新地址。

技術分享圖片

String類為什麽要被設計為是final的?

  1.不可變性支持線程安全
  2.不可變性支持字符串常量池,提升性能
  3.String字符串作為最常用數據類型之一,不可變防止了隨意修改,保證了數據的安全性

正常情況下Java的String字符串是final且不可變的。不過可以通過特殊手段修改它的內容。
String類的主力成員字段value是個char[ ]數組

,而且是用final修飾的。final修飾的字段創建以後就不可改變。因為雖然value是不可變,也只是value這個引用地址不可變。擋不住Array數組是可變的事實。Array的數據結構看下圖:

技術分享圖片

也就是說Array變量只是stack上的一個引用,數組的本體結構在heap堆。String類裏的value用final修飾,只是說stack裏的這個叫value的引用地址不可變。沒有說堆裏array本身數據不可變。

代碼測試:

 1 String test = "immutable String";
 2 String test1 = test;
 3 String test2 = new String(test);
4 String test3 = new String(test.toCharArray()); 5 Field values = String.class.getDeclaredField("value"); 6 values.setAccessible(true); 7 char[] chars = (char[])values.get(test); 8 chars[0] = u; 9 chars[1] = n; 10 System.out.println("test==test1:" + (test == test1)); 11 System.out.println("test==test2:
" + (test == test2)); 12 System.out.println("test1==test2:" + (test1 == test2)); 13 System.out.println("test:" + test + " test1:" + test1 + " test2:" + test2 + " test3:" + test3);

技術分享圖片

由String的不可變性引申到其他基本數據類型: Byte,Short,Integer,Long,Double,Float,Character,Boolean 八種基本數據的包裝類,仔細查看發現也是final修飾的,再仔細查看一下enum枚舉類型,發現用javac編譯後再用javap反編譯也是被編譯為final修飾的類,並且其枚舉值全部定義為static final 修飾的成員變量。

技術分享圖片

由此發現,Java設計者在設計Java基本數據類型時,把基本數據類型全部設計為不可變的,這樣既方便了開發人員,又保證了數據的安全性。

總結:Java中String是不可變的,但是可以通過反射修改其內容

備註:
作者:Shengming Zeng
博客:http://www.cnblogs.com/zengming/

本文是原創,歡迎大家轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明鏈接。
<歡迎有不同想法或見解的同學一起探討,共同進步>

在Java中String類為什麽要設計成final?String真的不可變嗎?其他基本類型的包裝類也是不可變的嗎?