日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

字符内存转成字符串_字符串内存内部

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字符内存转成字符串_字符串内存内部 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

字符內存轉成字符串

本文基于我對StackOverflow的回答 。 我正在嘗試解釋String類如何存儲文本,內部存儲和常量池如何工作。

這里要理解的要點是String Java對象與其內容– private value字段下的char[]之間的區別。 String基本上是char[]數組的包裝器,將其封裝并使其無法修改,因此String可以保持不變。 另外, String類還記住該數組的實際部分(請參閱下文)。 這一切都意味著您可以有兩個不同的String對象(相當輕量)指向相同的char[] 。

我會告訴你一些例子,連同hashCode()的每個String和hashCode()內部的char[] value字段(我將其稱之為文本字符串從區分)。 最后,我將顯示javap -c -verbose輸出以及測試類的常量池。 請不要將類常量池與字符串文字池混淆。 它們并不完全相同。 另請參見了解javap的常量池輸出 。

先決條件

為了進行測試,我創建了一個實用程序方法來破壞String封裝:

private int showInternalCharArrayHashCode(String s) {final Field value = String.class.getDeclaredField("value");value.setAccessible(true);return value.get(s).hashCode(); }

它將打印char[] value hashCode() ,有效地幫助我們了解此特定String是否指向相同的char[]文本。

一個類中的兩個字符串文字

讓我們從最簡單的示例開始。

Java代碼

String one = "abc"; String two = "abc";

順便說一句,如果您只寫"ab" + "c" ,則Java編譯器將在編譯時執行級聯,并且生成的代碼將完全相同。 僅當在編譯時知道所有字符串時,此方法才有效。

類常量池
每個類都有自己的常量池 -常量值列表,如果它們在源代碼中多次出現,則可以重用。 它包括常見的字符串,數字,方法名稱等。
這是上面示例中常量池的內容:

const #2 = String #38; // abc //... const #38 = Asciz abc;

要注意的重要事項是String常量對象( #2 )和字符串指向的Unicode編碼文本"abc" ( #38 )之間的區別。

字節碼
這是生成的字節碼。 請注意, one引用和two引用都分配有指向"abc"字符串的相同#2常量:

ldc #2; //String abc astore_1 //one ldc #2; //String abc astore_2 //two

輸出量
對于每個示例,我將打印以下值:

System.out.println("one.value: " + showInternalCharArrayHashCode(one)); System.out.println("two.value: " + showInternalCharArrayHashCode(two)); System.out.println("one" + System.identityHashCode(one)); System.out.println("two" + System.identityHashCode(two));

這兩對相等并不奇怪:

one.value: 23583040 two.value: 23583040 one: 8918249 two: 8918249

這意味著不僅兩個對象都指向相同的char[] (下面的相同文本),所以equals()測試將通過。 但更重要的是, one和two是完全相同的引用! 因此, one == two也是正確的。 顯然,如果one和two指向同一個對象,則one.value和two.value必須相等。

文字和new String() ?

Java代碼
現在,我們都在等待該示例–一個字符串文字和一個使用相同文字的新String 。 這將如何運作?

String one = "abc"; String two = new String("abc");

在源代碼中兩次使用了"abc"常量這一事實應該給您一些提示……

類常量池與上面相同。

字節碼

ldc #2; //String abc astore_1 //onenew #3; //class java/lang/String dup ldc #2; //String abc invokespecial #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V astore_2 //two

仔細地看! 第一個對象的創建方法與上面相同,不足為奇。 它只需要從常量池中常量引用已經創建的String ( #2 )。 但是,第二個對象是通過常規構造函數調用創建的。 但! 第一個String作為參數傳遞。 可以將其反編譯為:

String two = new String(one);

輸出量
輸出有點令人驚訝。 第二對表示對String對象的引用是可以理解的-我們創建了兩個String對象-一個在常量池中為我們創建,第二個是為two手動創建的。 但是,為什么第一對建議兩個String對象都指向同一個char[] value數組呢?

one.value: 41771 two.value: 41771 one: 8388097 two: 16585653

當您查看String(String)構造函數的工作原理時,這一點變得很清楚(此處已大大簡化了):

public String(String original) {this.offset = original.offset;this.count = original.count;this.value = original.value; }

看到? 當基于現有對象創建新的String對象時,它會重用 char[] value 。 String是不可變的,不需要復制已知永遠不會修改的數據結構。 而且,由于new String(someString)創建了現有字符串的精確副本,并且字符串是不可變的,因此顯然沒有理由同時存在兩者。
我認為這是一些誤解的線索:即使您有兩個String對象,它們仍可能指向相同的內容。 如您所見, String對象本身很小。

運行時修改和intern() ?

Java代碼
假設您最初使用了兩個不同的字符串,但是在進行一些修改之后,它們都是相同的:

String one = "abc"; String two = "?abc".substring(1); //also two = "abc"

Java編譯器(至少是我的)不夠聰明,無法在編譯時執行此類操作,請看一下:

類常量池
突然我們以指向兩個不同常量文本的兩個常量字符串結尾:

const #2 = String #44; // abc const #3 = String #45; // ?abc const #44 = Asciz abc; const #45 = Asciz ?abc;

字節碼

ldc #2; //String abc astore_1 //oneldc #3; //String ?abc iconst_1 invokevirtual #4; //Method String.substring:(I)Ljava/lang/String; astore_2 //two

拳頭弦照常構造。 通過首先加載常量"?abc"字符串,然后在其上調用substring(1)來創建第二個。

輸出量

這里不足為奇–我們有兩個不同的字符串,指向內存中兩個不同的char[]文本:

one.value: 27379847 two.value: 7615385 one: 8388097 two: 16585653

好吧,文本并沒有真正的不同 , equals()方法仍然會產生true 。 我們有兩個不必要的相同文本副本。
現在我們應該進行兩次練習。 首先,嘗試運行:

two = two.intern();

在打印哈希碼之前。 one和two不僅指向同一文本,而且它們是相同的參考!

one.value: 11108810 two.value: 11108810 one: 15184449 two: 15184449

這意味著one.equals(two)和one == two測試都將通過。 我們還節省了一些內存,因為"abc"文本在內存中僅出現一次(第二個副本將被垃圾回收)。
第二個練習略有不同,請查看以下內容:

String one = "abc"; String two = "abc".substring(1);

顯然one和two是兩個不同的對象,指向兩個不同的文本。 但是輸出如何表明它們都指向同一個char[]數組?!

one.value: 11108810 two.value: 8918249 one: 23583040 two: 23583040

我將答案留給你。 它會教您substring()工作原理,這種方法的優點是什么以及何時會導致大麻煩 。

得到教訓

  • String對象本身相當便宜。 它指向的文本占用了大部分內存
  • String只是char[]的薄包裝,以保持不變性
  • new String("abc")作為內部文本表示被重用是不是真的那么貴。 但是還是要避免這樣的構造。
  • 從編譯時已知的常量值連接String時,連接由編譯器而不是由JVM完成
  • substring()有點棘手,但最重要的是,就使用的內存和運行時間而言,它都很便宜(在兩種情況下均保持不變)

參考: Java和社區博客中來自JCG合作伙伴 Tomasz Nurkiewicz的字符串內存內部 。


翻譯自: https://www.javacodegeeks.com/2012/07/string-memory-internals.html

字符內存轉成字符串

總結

以上是生活随笔為你收集整理的字符内存转成字符串_字符串内存内部的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。