一、String是一個不可變類
我們都知道String是一個不可變類,因為它的源碼內部維護着一個final修飾的char數組,final修飾的變量不可以被改變,修飾的方法不可以被重寫,修飾的類不可以被繼承:(簡要源碼)
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[];
}
也就是說:String對象一旦創建,就不可改變。拼接、截取或者重新賦值都是在重新建對象。
做一下代碼演示:
/** * @Author 程Sir * @Version 2020年3月26日上午11:20:51 * @description 描述:字符串不可以被改變 */ public class Demo { public static void main(String[] args) throws IOException { String str = "不變的字符串"; System.out.println("1. " + str +" : " + str.hashCode()); str = str.substring(2); System.out.println("3. " + str +" : " + str.hashCode()); str = str+1; System.out.println("2. " + str +" : " + str.hashCode()); } }
輸出的結果是:
1. 不變的字符串 : 83361354
3. 的字符串 : 927327327
2. 的字符串1 : -1317623886
通過演示表明:hashcode值每次都是不一樣的。說明操作的不是同一對象,再次過程中有新的對象被創建。
二、應用Java中的反射機制
我們學習了反射機制,了解到:反射是在運行期能夠對類的屬性、方法進行操作。即:運行期綁定。那么我們是不是可以在String運行期對它的值進行一個完美操作了,答案是肯定的,完全可以的,看以下代碼:
/** * @Author 程Sir * @Version 2020年3月26日上午11:20:51 * @description 描述:字符串不可以被改變 */ public class Demo { public static void main(String[] args) throws IOException { String str = "不變的字符串"; System.out.println("1. " + str +" : " + str.hashCode()); try { //反射通過屬性拿到值,Sting類的屬性char數組的屬性名為:value Field field = str.getClass().getDeclaredField("value"); //設置該屬性為可操作 field.setAccessible(true); //改變該屬性的值:改變char數組 field.set(str, new char[]{'程','s','i','r'}); System.out.println("2. " + str+" : " + str.hashCode()); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
輸出的結果是:
1. 不變的字符串 : 83361354
2. 程sir : 83361354
從演示結果中,我們發現,字符串str的hashcode值兩次相等,並沒有發生改變,說明是同一對象,但前后的值(內容)完全是發生了改變。即達到了我們的目的:String類的值是可以通過Java的反射機制進行改變的。
三、總結
最后,我們做一個總結:
String類是用final關鍵字修飾的,那值就是不可以改變,值不可以改變,導向到結果是這個值的引用地址在內存中是不可被改變。再String類的本質是內部維護這一個char類型的數組,明確這點后,我們既可以通過Java反射機制的特性,在運行期對其內部的char數組內容進行操作,從而達到改變String類內容的目的。