欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JDK9為何要將String的底層實(shí)現(xiàn)由char[]改成了byte[]

 更新時(shí)間:2022年03月25日 09:43:06   作者:公眾號(hào)_IT老哥  
String 類的源碼已經(jīng)由?char[]?優(yōu)化為了?byte[]?來(lái)存儲(chǔ)字符串內(nèi)容,為什么要這樣做呢?本文就詳細(xì)的介紹一下,感興趣的可以了解一下

如果你不是 Java8 的釘子戶,你應(yīng)該早就發(fā)現(xiàn)了:String 類的源碼已經(jīng)由 char[] 優(yōu)化為了 byte[] 來(lái)存儲(chǔ)字符串內(nèi)容,為什么要這樣做呢?

開(kāi)門(mén)見(jiàn)山地說(shuō),從 char[] 到 byte[],最主要的目的是為了節(jié)省字符串占用的內(nèi)存。內(nèi)存占用減少帶來(lái)的另外一個(gè)好處,就是 GC 次數(shù)也會(huì)減少。

一、為什么要優(yōu)化 String 節(jié)省內(nèi)存空間

我們使用 jmap -histo:live pid | head -n 10 命令就可以查看到堆內(nèi)對(duì)象示例的統(tǒng)計(jì)信息、查看 ClassLoader 的信息以及 finalizer 隊(duì)列。

以我正在運(yùn)行著的編程喵喵項(xiàng)目實(shí)例(基于 Java 8)來(lái)說(shuō),結(jié)果是這樣的。

其中 String 對(duì)象有 17638 個(gè),占用了 423312 個(gè)字節(jié)的內(nèi)存,排在第三位。

由于 Java 8 的 String 內(nèi)部實(shí)現(xiàn)仍然是 char[],所以我們可以看到內(nèi)存占用排在第 1 位的就是 char 數(shù)組。

char[] 對(duì)象有 17673 個(gè),占用了 1621352 個(gè)字節(jié)的內(nèi)存,排在第一位。

那也就是說(shuō)優(yōu)化 String 節(jié)省內(nèi)存空間是非常有必要的,如果是去優(yōu)化一個(gè)使用頻率沒(méi)有 String 這么高的類庫(kù),就顯得非常的雞肋。

二、byte[] 為什么就能節(jié)省內(nèi)存空間呢?

眾所周知,char 類型的數(shù)據(jù)在 JVM 中是占用兩個(gè)字節(jié)的,并且使用的是 UTF-8 編碼,其值范圍在 '\u0000'(0)和 '\uffff'(65,535)(包含)之間。

也就是說(shuō),使用 char[] 來(lái)表示 String 就導(dǎo)致了即使 String 中的字符只用一個(gè)字節(jié)就能表示,也得占用兩個(gè)字節(jié)。

而實(shí)際開(kāi)發(fā)中,單字節(jié)的字符使用頻率仍然要高于雙字節(jié)的。

當(dāng)然了,僅僅將 char[] 優(yōu)化為 byte[] 是不夠的,還要配合 Latin-1 的編碼方式,該編碼方式是用單個(gè)字節(jié)來(lái)表示字符的,這樣就比 UTF-8 編碼節(jié)省了更多的空間。

換句話說(shuō),對(duì)于:

String name = "jack";  

這樣的,使用 Latin-1 編碼,占用 4 個(gè)字節(jié)就夠了。

但對(duì)于:

String name = "小二"; 

這種,木的辦法,只能使用 UTF16 來(lái)編碼。

針對(duì) JDK 9 的 String 源碼里,為了區(qū)別編碼方式,追加了一個(gè) coder 字段來(lái)區(qū)分。

/**  
 * The identifier of the encoding used to encode the bytes in  
 * {@code value}. The supported values in this implementation are  
 *  
 * LATIN1  
 * UTF16  
 *  
 * @implNote This field is trusted by the VM, and is a subject to  
 * constant folding if String instance is constant. Overwriting this  
 * field after construction will cause problems.  
 */  
private final byte coder; 

Java 會(huì)根據(jù)字符串的內(nèi)容自動(dòng)設(shè)置為相應(yīng)的編碼,要么 Latin-1 要么 UTF16。

也就是說(shuō),從 char[] 到 byte[],中文是兩個(gè)字節(jié),純英文是一個(gè)字節(jié),在此之前呢,中文是兩個(gè)字節(jié),英文也是兩個(gè)字節(jié)。

三、為什么用UTF-16而不用UTF-8呢?

在 UTF-8 中,0-127 號(hào)的字符用 1 個(gè)字節(jié)來(lái)表示,使用和 ASCII 相同的編碼。只有 128 號(hào)及以上的字符才用 2 個(gè)、3 個(gè)或者 4 個(gè)字節(jié)來(lái)表示。

  • 如果只有一個(gè)字節(jié),那么最高的比特位為 0;

  • 如果有多個(gè)字節(jié),那么第一個(gè)字節(jié)從最高位開(kāi)始,連續(xù)有幾個(gè)比特位的值為 1,就使用幾個(gè)字節(jié)編碼,剩下的字節(jié)均以 10 開(kāi)頭。

具體的表現(xiàn)形式為:

  • 0xxxxxxx:一個(gè)字節(jié);

  • 110xxxxx 10xxxxxx:兩個(gè)字節(jié)編碼形式(開(kāi)始兩個(gè) 1);- 1110xxxx 10xxxxxx 10xxxxxx:三字節(jié)編碼形式(開(kāi)始三個(gè) 1);

  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字節(jié)編碼形式(開(kāi)始四個(gè) 1)。

也就是說(shuō),UTF-8 是變長(zhǎng)的,那對(duì)于 String 這種有隨機(jī)訪問(wèn)方法的類來(lái)說(shuō),就很不方便。所謂的隨機(jī)訪問(wèn),就是charAt、subString這種方法,隨便指定一個(gè)數(shù)字,String要能給出結(jié)果。如果字符串中的每個(gè)字符占用的內(nèi)存是不定長(zhǎng)的,那么進(jìn)行隨機(jī)訪問(wèn)的時(shí)候,就需要從頭開(kāi)始數(shù)每個(gè)字符的長(zhǎng)度,才能找到你想要的字符。

那有小伙伴可能會(huì)問(wèn),UTF-16也是變長(zhǎng)的呢?一個(gè)字符還可能占用 4 個(gè)字節(jié)呢?

的確,UTF-16 使用 2 個(gè)或者 4 個(gè)字節(jié)來(lái)存儲(chǔ)字符。

  • 對(duì)于 Unicode 編號(hào)范圍在 0 ~ FFFF 之間的字符,UTF-16 使用兩個(gè)字節(jié)存儲(chǔ)。

  • 對(duì)于 Unicode 編號(hào)范圍在 10000 ~ 10FFFF 之間的字符,UTF-16 使用四個(gè)字節(jié)存儲(chǔ),具體來(lái)說(shuō)就是:將字符編號(hào)的所有比特位分成兩部分,較高的一些比特位用一個(gè)值介于 D800DBFF 之間的雙字節(jié)存儲(chǔ),較低的一些比特位(剩下的比特位)用一個(gè)值介于 DC00DFFF 之間的雙字節(jié)存儲(chǔ)。

但是在 Java 中,一個(gè)字符(char)就是 2 個(gè)字節(jié),占 4 個(gè)字節(jié)的字符,在 Java 里也是用兩個(gè) char 來(lái)存儲(chǔ)的,而String的各種操作,都是以Java的字符(char)為單位的,charAt是取得第幾個(gè)char,subString取的也是第幾個(gè)到第幾個(gè)char組成的子串,甚至length返回的都是char的個(gè)數(shù)。

所以UTF-16在Java的世界里,就可以視為一個(gè)定長(zhǎng)的編碼。

到此這篇關(guān)于JDK9為何要將String的底層實(shí)現(xiàn)由char[]改成了byte[]的文章就介紹到這了,更多相關(guān)JDK9 char[]改成了byte[]內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mybatis快速入門(mén)學(xué)習(xí)教程新手注意問(wèn)題小結(jié)

    mybatis快速入門(mén)學(xué)習(xí)教程新手注意問(wèn)題小結(jié)

    MyBatis 是支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的持久層框架。接下來(lái)通過(guò)本文給大家介紹mybatis快速入門(mén)學(xué)習(xí)教程新手注意問(wèn)題小結(jié),需要的朋友可以參考下
    2017-02-02
  • Java實(shí)現(xiàn)Executors類創(chuàng)建常見(jiàn)線程池

    Java實(shí)現(xiàn)Executors類創(chuàng)建常見(jiàn)線程池

    本文主要介紹了Java實(shí)現(xiàn)Executors類創(chuàng)建常見(jiàn)線程池,在Java中,可以通過(guò)Executors工廠類提供四種常見(jiàn)類型的線程池,下面就來(lái)介紹一下這四種的方法實(shí)現(xiàn),感興趣的可以了解一下
    2023-11-11
  • springboot中spring.profiles.include的妙用分享

    springboot中spring.profiles.include的妙用分享

    這篇文章主要介紹了springboot中spring.profiles.include的妙用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Java實(shí)現(xiàn)產(chǎn)生隨機(jī)字符串主鍵的UUID工具類

    Java實(shí)現(xiàn)產(chǎn)生隨機(jī)字符串主鍵的UUID工具類

    這篇文章主要介紹了Java實(shí)現(xiàn)產(chǎn)生隨機(jī)字符串主鍵的UUID工具類,涉及java隨機(jī)數(shù)與字符串遍歷、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • SpringBoot @Async如何自定義線程池及使用教程

    SpringBoot @Async如何自定義線程池及使用教程

    這篇文章主要介紹了SpringBoot @Async如何自定義線程池及使用教程,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • java基礎(chǔ)類型源碼解析之多角度講HashMap

    java基礎(chǔ)類型源碼解析之多角度講HashMap

    這篇文章主要給大家介紹了關(guān)于java基礎(chǔ)類型源碼解析之HashMap的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java基具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • JAVA-NIO之Socket/ServerSocket Channel(詳解)

    JAVA-NIO之Socket/ServerSocket Channel(詳解)

    下面小編就為大家?guī)?lái)一篇JAVA-NIO之Socket/ServerSocket Channel(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • SpringBoot中的內(nèi)容協(xié)商器圖解

    SpringBoot中的內(nèi)容協(xié)商器圖解

    本文通過(guò)圖文解說(shuō)加代碼的形式給大家介紹了SpringBoot中的內(nèi)容協(xié)商器知識(shí),需要的朋友參考下吧
    2017-11-11
  • 聊聊SpringBoot使用Nacos進(jìn)行服務(wù)注冊(cè)發(fā)現(xiàn)與配置管理問(wèn)題

    聊聊SpringBoot使用Nacos進(jìn)行服務(wù)注冊(cè)發(fā)現(xiàn)與配置管理問(wèn)題

    Nacos支持基于DNS和基于RPC的服務(wù)發(fā)現(xiàn)(可以作為springcloud的注冊(cè)中心)、動(dòng)態(tài)配置服務(wù)(可以做配置中心)、動(dòng)態(tài)?DNS?服務(wù)。本文重點(diǎn)給大家介紹SpringBoot使用Nacos進(jìn)行服務(wù)注冊(cè)發(fā)現(xiàn)與配置管理,感興趣的朋友一起看看吧
    2022-01-01
  • Java實(shí)現(xiàn)優(yōu)雅停止線程的有效方法詳解

    Java實(shí)現(xiàn)優(yōu)雅停止線程的有效方法詳解

    這篇文章主要為大家詳細(xì)如何安全有效停止 Java 線程的,確保多線程應(yīng)用程序平穩(wěn)運(yùn)行并實(shí)現(xiàn)最佳資源管理,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12

最新評(píng)論