JavaRush /Java Blog /Random-TW /子字串(..)困擾著我
IgorBrest
等級 33

子字串(..)困擾著我

在 Random-TW 群組發布
實際上,由於主題的原因,我允許自己深入研究 String.substring(..)。我可能得到了意想不到的結果,我決定與你們分享,親愛的 Javorashovites。可以這麼說,將其​​呈現給您的判斷。所以就是這樣。有一種說法是,使用 substring(..) 方法建立的字串使用原始字串的字元陣列。這裡特別摘錄自最近閱讀的文章“Java Reference.Static Strings”,作者是受人尊敬的文章
關於 substring 方法有一個註解 - 傳回的字串使用與原始字串相同的位元組數組
當然,還有 Javarash 講座。以下是 12 月 22 日的引述:
當我們使用 substring 方法建立子字串時,就會建立一個新的 String 物件。但是,該物件不是儲存對具有新字元集的數組的引用,而是儲存對舊字元數組的引用,同時儲存兩個變量,用於確定原始字元數組的哪一部分屬於它。...建立子字串時,字元陣列不會複製到新的 String 物件。相反,兩個物件都儲存對相同字元數組的引用。但!第二個物件儲存另外兩個變量,其中包含要寫入該數組的哪些字元以及多少個字元。……因此,如果你取一個 10,000 個字元長的字串並從中產生 10,000 個任意長度的子字串,那麼這些「子字串」將佔用很少的內存,因為 字元數組不重複。應該佔用大量空間的字串只會佔用幾個位元組。
一切都寫得很清楚,甚至連咀嚼過。但是,由於我正在努力提高我的英語知識,我經常查閱官方文檔,但不知何故我找不到這個事實的確認......將這歸因於我的粗心,我仍然查看了源代碼substring()(感謝IDEA 允許您透過點擊按鈕來完成此操作)。 public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); } 出於好奇,我更進一步: * Allocates a new {@code String} that contains characters from a subarray * of the character array argument. The {@code offset} argument is the * index of the first character of the subarray and the {@code count} * argument specifies the length of the subarray. The contents of the * subarray are copied; subsequent modification of the character array does * not affect the newly created string. public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count < 0) { throw new StringIndexOutOfBoundsException(count); } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.value = Arrays.copyOfRange(value, offset, offset+count); } 其中Arrays.copyOfRange 是一個本機方法,它從char 返回數組的副本...相當簡單的程式碼,對我來說很明顯,簡單地創建了帶有一組新字元的新行。或者我沒有考慮到某些事情......所以,不完全相信我的結論,我決定以某種方式測試這個 substring() ,依靠講座中的一個短語:
因此,如果你取一個 10,000 個字元長的字串並從中產生 10,000 個任意長度的子字串,那麼這些「子字串」將佔用很少的記憶體...
只是我們會立即獲得 100_000_000,而不是 10_000,為什麼要在瑣事上浪費時間。我很快輸入了以下程式碼: 這就是發生的事情: 即 每次使用 bigString.substring(..) 建立新的子字串時,字元陣列都會重複。我們還能如何解釋記憶體消耗的這種增加?從此以後,我個人對 String.substsring() 方法的操作不再有任何疑問,你呢? public class Test { public static void main(String[] args) { System.out.println("Начинаем:"); print(); System.out.println("********************************"); char[]big=new char[100_000_000];//создаем нормальный такой массив int j=0;//и заполняем этот массив всякой ерундой for (int k=0;k list=new ArrayList<>();//здесь будут ссылки на строки, что бы сборщик мусора не удалял //не используемые, по его мнению, строки. System.out.println("************************************"); System.out.println("Теперь будем создавть подстроки с помощью substring(..) и наблюдать," + "что же происходит с памятью"); for (int i = 2; i <10; i++) { //создаем подстроку, используя метод String.substring(..) String sub= bigString.substring(1,bigString.length()-1); //если этот метод не создает fully новый массив символов, а только пользуется //исходным из bigString // то при создании новой строки sub мы не будем наблюдать ощутипый расход памяти list.add(sub);//эти ссылки мы должны где нибудь хранить, иначе сборщик мусора //избавится от неипользуемых объктов String System.out.print(String.format("Создаем %d-ую подстроку, при этом ", i - 1)); print(); } System.out.println("***************************************"); print(); } static void print(){ System.out.println("Памяти используется "+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024/1024 + " mb"); } } Начинаем: Памяти используется 0 mb ******************************** создал большую строку bigString на основе массива big. Теперь: Памяти используется 382 mb ************************************ Теперь будем создавть подстроки с помощью substring(..) и наблюдать,что же происходит с памятью Добавляем 1-ую подстроку, при этом Памяти используется 573 mb Добавляем 2-ую подстроку, при этом Памяти используется 763 mb Добавляем 3-ую подстроку, при этом Памяти используется 954 mb Добавляем 4-ую подстроку, при этом Памяти используется 1145 mb Добавляем 5-ую подстроку, при этом Памяти используется 1336 mb Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOfRange(Arrays.java:3658) at java.lang.String. (String.java:201) at java.lang.String.substring(String.java:1956) at com.javarush.test.tests.Test.main(Test.java:42) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) Process finished with exit code 1
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION