最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?常量池詳解之字符串常量池實現(xiàn)代碼

 更新時間:2022年12月27日 10:30:08   作者:new?hilbert()  
這篇文章主要介紹了Java?常量池詳解之字符串常量池,本文結合示例代碼對java字符串常量池相關知識講解的非常詳細,需要的朋友可以參考下

在Java的內(nèi)存分配中,總共3種常量池:

Java 常量池詳解(二)class文件常量池 和 Java 常量池詳解(三)class運行時常量池

1.字符串常量池(String Constant Pool)

在JDK1.7之前運行時常量池邏輯包含字符串常量池存放在方法區(qū), 此時hotspot虛擬機對方法區(qū)的實現(xiàn)為永久代
在JDK1.7 字符串常量池被從方法區(qū)拿到了堆中, 這里沒有提到運行時常量池,也就是說字符串常量池被單獨拿到堆,運行時常量池剩下的東西還在方法區(qū), 也就是hotspot中的永久代
在JDK1.8 hotspot移除了永久代用元空間(Metaspace)取而代之, 這時候字符串常量池還在堆, 運行時常量池還在方法區(qū), 只不過方法區(qū)的實現(xiàn)從永久代變成了元空間(Metaspace)

在這里插入圖片描述

1.1:字符串常量池在Java內(nèi)存區(qū)域的哪個位置?

  • 在JDK6.0及之前版本,字符串常量池是放在Perm Gen區(qū)(也就是方法區(qū))中;

  • 在JDK7.0版本,字符串常量池被移到了堆中了。至于為什么移到堆內(nèi),大概是由于方法區(qū)的內(nèi)存空間太小了。
  • (堆內(nèi)是可以進行回收的,然后方法區(qū)也是能回收的,但是本身區(qū)域內(nèi)存比較少,如果用的字符串常量太多了,也會拋java.lang.OutOfMemoryError:PermGenspace 異常)

1.2:字符串常量池是什么?

  • 在HotSpot VM里實現(xiàn)的string pool功能的是一個StringTable類,它是一個Hash表,默認值大小長度是1009;這個StringTable在每個HotSpot VM的實例只有一份,被所有的類共享。字符串常量由一個一個字符組成,放在了StringTable上。
  • 在JDK6.0中,StringTable的長度是固定的,長度就是1009,因此如果放入String Pool中的String非常多,就會造成hash沖突,導致鏈表過長,當調用String#intern()時會需要到鏈表上一個一個找,從而導致性能大幅度下降;
  • 在JDK7.0中,StringTable的長度可以通過參數(shù)指定:
-XX:StringTableSize=66666`

1.3 字符串常量池生成的時機?

String a = "a";

在這里插入圖片描述

全局字符串池里的內(nèi)容是在類加載完成,經(jīng)過驗證,準備階段之后在堆中生成字符串對象實例,然后將該字符串對象實例的引用值存到string pool中(記?。簊tring pool中存的是引用值而不是具體的實例對象,具體的實例對象是在堆中開辟的一塊空間存放的)

在這里插入圖片描述

如何將String對象放入到常量池

  • “abc” 雙引號String 對象會自動放入常量池
  • 調用String的intern 方法也會將對象放入到常量池中

String 對象代碼案例解析

public static void main(String[] args) {
    String a = "a";
    String b = "b";
    String c = "a" + "b";
    //生成兩個對象 一個"ab" ,一個新的String 對象value 值是ab
    //public String(String original) {
    //   this.value = original.value;
    //   this.hash = original.hash;
    //}
    String d = new String("ab"); 
    
    String e = a + "b";
    String f = a + b;
    String g = "ab";
    
   System.out.println(e == c);
   System.out.println(c == d);
   System.out.println(f == c);
   System.out.println(g == c);
   
   String e1 = e.intern();
   String c2 = c.intern();
   System.out.println(e1 == c2);
   System.out.println(e1 == c);
}

//運行結果
false
false
false
true
true
true

String c =“a” + “b” 和String c = “a” + b (String b= “b”)的區(qū)別

String b = "b";
String c = "a" + "b"; 等價于 String c ="ab"
String c1 = "a" + b; 
 
// java 反編譯的結果  
 0 ldc #3 <b> //load constant  加載常量 "b"
 2 astore_1   // 存入變量1中
 3 ldc #4 <ab> //自動識別了 
 5 astore_2
 6 new #7 <java/lang/StringBuilder>
 9 dup
10 invokespecial #8 <java/lang/StringBuilder.<init>>
13 ldc #2 <a>
15 invokevirtual #9 <java/lang/StringBuilder.append>
18 aload_1
19 invokevirtual #9 <java/lang/StringBuilder.append>
22 invokevirtual #10 <java/lang/StringBuilder.toString>
25 astore_3
26 return

(1) “a”+“b” 編譯器自動識別了變成了 “ab” => 3 ldc #4
(2) “a” + b(變量)

  • 先new 了StringBuilder 對象,并初始化init
  • 然后bulider.append(“a”)
  • 從變量1(b)中取出值"b"
  • 然后執(zhí)行了bulider.append(“b”)
  • 最后執(zhí)行了builder.toString() 方法 給變量3( c1)進行賦值

new string(“abc”)創(chuàng)建了幾個對象

答案:是兩個 ,new string(xxxx)方法,xxxx傳入的是String對象。說明xxxx也是String對象。

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

String 是一個final 類型對象是不會變化的,如果發(fā)生變化,說明其實是新的對象。

public final class String

解析public native String intern() 方法

如果常量池中存在當前字符串, 就會直接返回當前字符串. 如果常量池中沒有此字符串, 會將此字符串放入常量池中后, 再返回

native實現(xiàn)代碼:

\openjdk7\jdk\src\share\native\java\lang\String.c


Java_java_lang_String_intern(JNIEnv *env, jobject this) 
{ 
    return JVM_InternString(env, this); 
}

\openjdk7\hotspot\src\share\vm\prims\jvm.h

JNIEXPORT jstring JNICALL 
JVM_InternString(JNIEnv *env, jstring str);

\openjdk7\hotspot\src\share\vm\prims\jvm.cpp

JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str)) 
  JVMWrapper("JVM_InternString"); 
  JvmtiVMObjectAllocEventCollector oam; 
  if (str == NULL) return NULL; 
  oop string = JNIHandles::resolve_non_null(str); 
  //調用StringTable::intern 方法
  oop result = StringTable::intern(string, CHECK_NULL);
  return (jstring) JNIHandles::make_local(env, result); 
JVM_END

\openjdk7\hotspot\src\share\vm\classfile\symbolTable.cpp

oop StringTable::intern(Handle string_or_null, jchar* name, int len, TRAPS) { 
  //根據(jù)名字找到對應hash下標
  unsigned int hashValue = java_lang_String::hash_string(name, len); 
  int index = the_table()->hash_to_index(hashValue); 
  //順著對應的鏈表查找對應的值
    oop string = the_table()->lookup(index, name, len, hashValue); 
  // Found 
  if (string != NULL) return string; 
  // Otherwise, add to symbol to table 
  return the_table()->basic_add(index, string_or_null, name, len, 
                                hashValue, CHECK_NULL); 
}

\openjdk7\hotspot\src\share\vm\classfile\symbolTable.cpp

oop StringTable::lookup(int index, jchar* name, int len, unsigned int hash) { 
  for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) { 
    if (l->hash() == hash) { 
      if (java_lang_String::equals(l->literal(), name, len)) { 
        return l->literal(); 
      } 
    } 
  } 
  return NULL; 
}

1.它的大體實現(xiàn)結構就是:JAVA 使用 jni 調用c++實現(xiàn)的StringTable的intern方法。

2.要注意的是,String的String Pool是一個固定大小的Hashtable,默認值大小長度是1009,如果放進String Pool的String非常多,就會造成Hash沖突嚴重,從而導致鏈表會很長,而鏈表長了后直接會造成的影響就是當調用String.intern時性能會大幅下降。

Interger 包裝類的池化技術


public final class Integer extends Number implements Comparable<Integer> {
   
    @Native public static final int   MIN_VALUE = 0x80000000;

  
    @Native public static final int   MAX_VALUE = 0x7fffffff;

    //緩存-128到127的值在IntegerCache里面,可以進行共享
    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
    
        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;
    
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
    
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }
    
        private IntegerCache() {}
    }
    
    public static Integer valueOf(int i) {
        //是不是在-128到127里面,不是的話就生成新的Integer
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
}        

Integer 對象代碼案例解析

public void test(){
    Integer i1 = 10;
    Integer i2 = 10;
    Integer i3 = new Integer(10);//新對象
    Integer i4 = new Integer(10);//新對象
    Integer i5 = Integer.valueOf(10);//從緩存池里面獲取。
    Integer i6 = Integer.valueOf(128);
    Integer i7 = 128;

    System.out.println(i1 == i2); // true
    System.out.println(i2 == i3); // false
    System.out.println(i3 == i4); // false
    System.out.println(i1 == i5); // true
    System.out.println(i6 == i7); // false
}

//運行結果:
true
false
false
true
false

為啥Integer i1 =10 跟Integer.valueOf(10) 是相等的?

因為Integer i1 = 10 底層原理是 Integer i1 = Integer.valueof(10)

  //Integer i1 =10 反編譯的結果
  0 bipush 10
  2 invokestatic #14 <java/lang/Integer.valueOf> //調用了Integer.valueof方法
  5 astore_1

為啥Integer i1 =128 跟Integer.valueOf(128) 是不相等的?

因為超過-128~127 這個范圍,就不在緩存池里面,不能共享都是新new 出來的

public static Integer valueOf(int i) {
        //是不是在-128到127里面,不是的話就生成新的Integer
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

問題:包裝類對象池是不是 JVM 常量池的一種?

  • 包裝類的對象池是池化技術的應用,并非是虛擬機層面的東西,而是 Java 在類封裝里實現(xiàn)的,IntegerCache 是 Integer在內(nèi)部維護的一個靜態(tài)內(nèi)部類,用于對象緩存。
  • Integer 對象池在底層實際上就是一個變量名為 cache 的數(shù)組,里面包含了 -128 ~ 127 的 Integer 對象實例。使用對象池的方法就是通過 Integer.valueOf() 返回 cache 中的對象,像 Integer i = 10這種自動裝箱實際上也是調用 Integer.valueOf() 完成的
  • 這和常量池中字面量的保存有很大區(qū)別,Integer 不需要顯示地出現(xiàn)在代碼中才添加到池中,初始化時它已經(jīng)包含了所有需要緩存的對象

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

相關文章

  • mybatis插入后返回主鍵id的3種方式圖解

    mybatis插入后返回主鍵id的3種方式圖解

    這篇文章主要給大家介紹了關于mybatis插入后返回主鍵id的3種方式,很多時候,在向數(shù)據(jù)庫插入數(shù)據(jù)時,需要保留插入數(shù)據(jù)的,以便進行后續(xù)的操作或者將存入其他表作為外鍵,需要的朋友可以參考下
    2023-08-08
  • 在項目中集成jetty server步驟解析

    在項目中集成jetty server步驟解析

    這篇文章主要介紹了在項目中集成jetty server步驟解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-02-02
  • 關于knife4j的使用及配置

    關于knife4j的使用及配置

    這篇文章主要介紹了關于knife4j的使用及配置,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • java實現(xiàn)ssh連接服務器的方法步驟

    java實現(xiàn)ssh連接服務器的方法步驟

    本文主要介紹了java實現(xiàn)ssh連接服務器的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-09-09
  • Java中的服務發(fā)現(xiàn)與負載均衡及Eureka與Ribbon的應用小結

    Java中的服務發(fā)現(xiàn)與負載均衡及Eureka與Ribbon的應用小結

    這篇文章主要介紹了Java中的服務發(fā)現(xiàn)與負載均衡:Eureka與Ribbon的應用,通過使用Eureka和Ribbon,我們可以在Java項目中實現(xiàn)高效的服務發(fā)現(xiàn)和負載均衡,需要的朋友可以參考下
    2024-08-08
  • java實現(xiàn)Socket通信之單線程服務

    java實現(xiàn)Socket通信之單線程服務

    這篇文章主要為大家詳細介紹了java實現(xiàn)Socket通信的單線程服務,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • java管道piped輸入流與輸出流應用場景案例分析

    java管道piped輸入流與輸出流應用場景案例分析

    這篇文章主要介紹了java管道流PipedInputStream與PipedOutputStream(輸入流與輸出流)的應用場景案例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-02-02
  • Java高效實現(xiàn)電商產(chǎn)品排序實戰(zhàn)

    Java高效實現(xiàn)電商產(chǎn)品排序實戰(zhàn)

    這篇文章主要為大家介紹了Java高效實現(xiàn)電商產(chǎn)品排序實戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • SpringBoot集成MQTT示例詳解

    SpringBoot集成MQTT示例詳解

    這篇文章主要為大家介紹了SpringBoot集成MQTT示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • JavaWeb開發(fā)中alias攔截器的使用方法

    JavaWeb開發(fā)中alias攔截器的使用方法

    本文給大家介紹在JavaWeb開發(fā)中alias攔截器的使用方法相關知識,本文介紹的非常詳細,具有參考借鑒價值,感興趣的朋友一起看下吧
    2016-08-08

最新評論

绥江县| 乌什县| 四子王旗| 定西市| 麦盖提县| 通江县| 措勤县| 余庆县| 合阳县| 施秉县| 皋兰县| 延边| 县级市| 太仆寺旗| 视频| 类乌齐县| 永春县| 保德县| 马龙县| 永胜县| 乌兰浩特市| 彭阳县| 潜山县| 蓬溪县| 兴文县| 屏东市| 治多县| 平南县| 嵊泗县| 泸溪县| 红桥区| 西峡县| 太谷县| 青田县| 乡宁县| 德清县| 新丰县| 新龙县| 庆城县| 咸阳市| 北宁市|