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

JAVA中的字符串常量池使用操作代碼

 更新時(shí)間:2022年12月27日 08:51:41   作者:JAVA旭陽(yáng)  
Java中的字符串常量池是Java堆中的一塊特殊存儲(chǔ)區(qū)域,用于存儲(chǔ)字符串。它的實(shí)現(xiàn)是為了提高字符串操作的性能并節(jié)省內(nèi)存,這篇文章主要介紹了JAVA中的字符串常量池,需要的朋友可以參考下

前言

研究表明,Java堆中對(duì)象占據(jù)最大比重的就是字符串對(duì)象,所以弄清楚字符串知識(shí)很重要,本文主要重點(diǎn)聊聊字符串常量池。Java中的字符串常量池是Java堆中的一塊特殊存儲(chǔ)區(qū)域,用于存儲(chǔ)字符串。它的實(shí)現(xiàn)是為了提高字符串操作的性能并節(jié)省內(nèi)存。它也被稱為String Intern PoolString Constant Pool。那讓我來(lái)看看究竟是怎么一回事吧。

理解字符串常量池

當(dāng)您從在類(lèi)中寫(xiě)一個(gè)字符串字面量時(shí),JVM將首先檢查該字符串是否已存在于字符串常量池中,如果存在,JVM 將返回對(duì)現(xiàn)有字符串對(duì)象的引用,而不是創(chuàng)建新對(duì)象。我們通過(guò)一個(gè)例子更好的來(lái)理解。

比如下面的代碼:

String s1 = "Harry Potter";
String s2 = "The Lord of the Rings";
String s3 = "Harry Potter";

在這段代碼中,JVM 將創(chuàng)建一個(gè)值為“Harry Potter”的字符串對(duì)象,并將其存儲(chǔ)在字符串常量池中。s1和s3都將是對(duì)該單個(gè)字符串對(duì)象的引用。

如果s2的字符串內(nèi)容“The Lord of the Rings”不存在于池中,則在字符串池中生成一個(gè)新的字符串對(duì)象。

兩種創(chuàng)建字符串方式

Java 編程語(yǔ)言中有兩種創(chuàng)建 String 的方法。第一種方式是使用String Literal字符串字面量的方式,另一種方式是使用new關(guān)鍵字。他們創(chuàng)建的字符串對(duì)象是都在常量池中嗎?

字符串字面量的方式創(chuàng)建

String s1 = "Harry Potter";
String s2 = "The Lord of the Rings";
String s3 = "Harry Potter";

new關(guān)鍵字創(chuàng)建

String s4 = new String("Harry Potter");
String s5 = new String("The Lord of the Rings");

我們來(lái)比較下他們引用的是否是同一個(gè)對(duì)象:

s1==s3 //真
s1==s4 //假
s2==s5 //假

使用 == 運(yùn)算符比較兩個(gè)對(duì)象時(shí),它會(huì)比較內(nèi)存中的地址。

正如您在上面的圖片和示例中看到的,每當(dāng)我們使用new運(yùn)算符創(chuàng)建字符串時(shí),它都會(huì)在 Java 堆中創(chuàng)建一個(gè)新的字符串對(duì)象,并且不會(huì)檢查該對(duì)象是否在字符串常量池中。

那么我現(xiàn)在有個(gè)問(wèn)題,如果是字符串拼接的情況,又是怎么樣的呢?

字符串拼接方式

前面講清楚了通過(guò)直接用字面量的方式,也就是引號(hào)的方式和用new關(guān)鍵字創(chuàng)建字符串,他們創(chuàng)建出的字符串對(duì)象在堆中存儲(chǔ)在不同的地方,那么我們現(xiàn)在來(lái)看看用+這個(gè)運(yùn)算符拼接會(huì)怎么樣。

例子1

public static void test1() {
      // 都是常量,前端編譯期會(huì)進(jìn)行代碼優(yōu)化
      // 通過(guò)idea直接看對(duì)應(yīng)的反編譯的class文件,會(huì)顯示 String s1 = "abc"; 說(shuō)明做了代碼優(yōu)化
      String s1 = "a" + "b" + "c";  
      String s2 = "abc"; 
  
      // true,有上述可知,s1和s2實(shí)際上指向字符串常量池中的同一個(gè)值
      System.out.println(s1 == s2); 
  }

常量與常量的拼接結(jié)果在常量池,原理是編譯期優(yōu)化。

例子2

public static void test5() {
    String s1 = "javaEE";
    String s2 = "hadoop";

    String s3 = "javaEEhadoop";
    String s4 = "javaEE" + "hadoop";    
    String s5 = s1 + "hadoop";
    String s6 = "javaEE" + s2;
    String s7 = s1 + s2;

    System.out.println(s3 == s4); // true 編譯期優(yōu)化
    System.out.println(s3 == s5); // false s1是變量,不能編譯期優(yōu)化
    System.out.println(s3 == s6); // false s2是變量,不能編譯期優(yōu)化
    System.out.println(s3 == s7); // false s1、s2都是變量
    System.out.println(s5 == s6); // false s5、s6 不同的對(duì)象實(shí)例
    System.out.println(s5 == s7); // false s5、s7 不同的對(duì)象實(shí)例
    System.out.println(s6 == s7); // false s6、s7 不同的對(duì)象實(shí)例
}

只要其中有一個(gè)是變量,結(jié)果就在堆中, 變量拼接的底層原理其實(shí)是StringBuilder。

例子3:

public void test6(){
    String s0 = "beijing";
    String s1 = "bei";
    String s2 = "jing";
    String s3 = s1 + s2;
    System.out.println(s0 == s3); // false s3指向?qū)ο髮?shí)例,s0指向字符串常量池中的"beijing"
    String s7 = "shanxi";
    final String s4 = "shan";
    final String s5 = "xi";
    String s6 = s4 + s5;
    System.out.println(s6 == s7); // true s4和s5是final修飾的,編譯期就能確定s6的值了
}
  • 不使用final修飾,即為變量。如s3行的s1和s2,會(huì)通過(guò)new StringBuilder進(jìn)行拼接
  • 使用final修飾,即為常量。會(huì)在編譯器進(jìn)行代碼優(yōu)化。

妙用String.intern() 方法

前面提到new關(guān)鍵字創(chuàng)建出來(lái)的字符串對(duì)象以及某些和變量進(jìn)行拼接不會(huì)在字符串常量池中,而是直接在堆中新建了一個(gè)對(duì)象。這樣不大好,做不到復(fù)用,節(jié)約不了空間。那有什么好辦法呢?intern()就派上用場(chǎng)了,這個(gè)非常有用。

intern()方法的作用可以理解為主動(dòng)將常量池中還沒(méi)有的字符串對(duì)象放入池中,并返回此對(duì)象地址。

String s6 = new String("The Lord of the Rings").intern();

s2==s6 //真
s2==s5 //假

字符串常量池有多大?

關(guān)于字符串常量池究竟有多大,我也說(shuō)不上來(lái),但是講清楚它底層的數(shù)據(jù)結(jié)構(gòu),也許你就明白了。

字符串常量池是一個(gè)固定大小的HashTable,哈希表,默認(rèn)值大小長(zhǎng)度是1009。如果放進(jìn)String PoolString非常多,就會(huì)造成Hash沖突嚴(yán)重,從而導(dǎo)致鏈表會(huì)很長(zhǎng),而鏈表長(zhǎng)了后直接會(huì)造成的影響就是當(dāng)調(diào)用String.intern時(shí)性能會(huì)大幅下降。

使用-XX:StringTablesize可設(shè)置StringTable的長(zhǎng)度

  • 在jdk6中StringTable是固定的,就是1009的長(zhǎng)度,所以如果常量池中的字符串過(guò)多就會(huì)導(dǎo)致效率下降很快。StringTable Size設(shè)置沒(méi)有要求
  • 在jdk7中,StringTable的長(zhǎng)度默認(rèn)值是60013,StringTable Size設(shè)置沒(méi)有要求

● 在jdk8中,設(shè)置StringTable長(zhǎng)度的話,1009是可以設(shè)置的最小值

字符串常量池的優(yōu)缺點(diǎn)

字符串池的優(yōu)點(diǎn)

  • 提高性能。由于 JVM 可以返回對(duì)現(xiàn)有字符串對(duì)象的引用而不是創(chuàng)建新對(duì)象,因此使用字符串池時(shí)字符串操作更快。
  • 共享字符串,節(jié)省內(nèi)存。字符串池允許您在不同的變量和對(duì)象之間共享字符串,通過(guò)避免創(chuàng)建不必要的字符串對(duì)象來(lái)幫助節(jié)省內(nèi)存。

字符串池的缺點(diǎn)

  • 它有可能導(dǎo)致性能下降。從池中檢索字符串需要搜索池中的所有字符串,這可能比簡(jiǎn)單地創(chuàng)建一個(gè)新的字符串對(duì)象要慢。如果程序創(chuàng)建和丟棄大量字符串,則尤其如此,因?yàn)槊看问褂米址畷r(shí)都需要搜索字符串池。

總結(jié)

其實(shí)在 Java 7 之前,JVM將 Java String Pool 放置在PermGen空間中,它具有固定大小——它不能在運(yùn)行時(shí)擴(kuò)展,也不符合垃圾回收的條件。在PermGen(而不是堆)中駐留字符串的風(fēng)險(xiǎn)是,如果我們駐留太多字符串,我們可能會(huì)從 JVM 得到一個(gè)OutOfMemory錯(cuò)誤。從 Java 7 開(kāi)始,Java String Pool存放在Heap空間,由 JVM進(jìn)行垃圾回收。這種方法的優(yōu)點(diǎn)是降低了OutOfMemory錯(cuò)誤的風(fēng)險(xiǎn),因?yàn)槲匆玫淖址畬某刂袆h除,從而釋放內(nèi)存。

現(xiàn)在通過(guò)本文的學(xué)習(xí),你該知道如何更好的創(chuàng)建字符串對(duì)象了吧。

到此這篇關(guān)于JAVA中的字符串常量池的文章就介紹到這了,更多相關(guān)java字符串常量池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java應(yīng)用cpu占用過(guò)高問(wèn)題分析及解決方法

    java應(yīng)用cpu占用過(guò)高問(wèn)題分析及解決方法

    這篇文章主要介紹了java應(yīng)用cpu占用過(guò)高問(wèn)題分析及解決方法,具有一定參考價(jià)值,需要的朋友可以參考下。
    2017-09-09
  • java8?stream排序以及自定義比較器方式

    java8?stream排序以及自定義比較器方式

    這篇文章主要介紹了java8?stream排序以及自定義比較器方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • springboot配置多數(shù)據(jù)源的實(shí)例(MongoDB主從)

    springboot配置多數(shù)據(jù)源的實(shí)例(MongoDB主從)

    下面小編就為大家分享一篇springboot配置多數(shù)據(jù)源的實(shí)例(MongoDB主從),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • JMagick實(shí)現(xiàn)基本圖像處理的類(lèi)實(shí)例

    JMagick實(shí)現(xiàn)基本圖像處理的類(lèi)實(shí)例

    這篇文章主要介紹了JMagick實(shí)現(xiàn)基本圖像處理的類(lèi),實(shí)例分析了java圖像處理的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • Java通過(guò)Freemarker模板實(shí)現(xiàn)生成Word文件

    Java通過(guò)Freemarker模板實(shí)現(xiàn)生成Word文件

    FreeMarker是一款模板引擎: 即一種基于模板和要改變的數(shù)據(jù), 并用來(lái)生成輸出文本的通用工具。本文將根據(jù)Freemarker模板實(shí)現(xiàn)生成Word文件,需要的可以參考一下
    2022-09-09
  • SpringBoot中驗(yàn)證用戶上傳的圖片資源的方法

    SpringBoot中驗(yàn)證用戶上傳的圖片資源的方法

    這篇文章主要介紹了在SpringBoot中驗(yàn)證用戶上傳的圖片資源,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • 排序算法圖解之Java快速排序的分步刨析

    排序算法圖解之Java快速排序的分步刨析

    快速排序是通過(guò)一趟排序?qū)⒁判虻臄?shù)據(jù)分割為獨(dú)立的兩個(gè)部分,一部分的所有數(shù)據(jù)比另外一部分的所有數(shù)據(jù)要小,然后按照此方法對(duì)這兩部分分別進(jìn)行快速排序,整個(gè)過(guò)程可以遞歸進(jìn)行,以此達(dá)到整個(gè)數(shù)據(jù)變成有序序列。本文通過(guò)示例講解了快速排序的實(shí)現(xiàn),需要的可以參考一下
    2022-11-11
  • java分布式面試系統(tǒng)限流最佳實(shí)踐

    java分布式面試系統(tǒng)限流最佳實(shí)踐

    這篇文章主要介紹了java分布式面試系統(tǒng)限流最佳實(shí)踐場(chǎng)景分析解答,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-03-03
  • Java?Stream對(duì)象并行處理方法parallel()代碼示例

    Java?Stream對(duì)象并行處理方法parallel()代碼示例

    在Java中Stream是一種用于處理集合數(shù)據(jù)的流式操作API,它提供了一種簡(jiǎn)潔、靈活、高效的方式來(lái)對(duì)集合進(jìn)行各種操作,下面這篇文章主要給大家介紹了關(guān)于Java?Stream對(duì)象并行處理方法parallel()的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • Mybatis-Plus?動(dòng)態(tài)表名的實(shí)踐

    Mybatis-Plus?動(dòng)態(tài)表名的實(shí)踐

    本文主要介紹了Mybatis-Plus?動(dòng)態(tài)表名的實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08

最新評(píng)論