1. 程式人生 > >常量池與執行時常量池

常量池與執行時常量池

一、執行時常量池簡介

執行時常量池(Runtime Constant Pool),它是方法區的一部分。Class檔案中除了有類的版本、欄位、方法、介面等描述等資訊外,還有一項資訊是常量池(Constant Pool Table),用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類載入後存放到常量池中

執行時常量是相對於常量來說的,它具備一個重要特徵是:動態性。當然,值相同的動態常量與我們通常說的常量只是來源不同,但是都是儲存在池內同一塊記憶體區域。Java語言並不要求常量一定只能在編譯期產生,執行期間也可能產生新的常量,這些常量被放在執行時常量池中。這裡所說的常量包括:基本型別包裝類

(包裝類不管理浮點型,整形只會管理-128到127)和String(也可以通過String.intern()方法可以強制將String放入常量池)

二、 Class檔案中的資訊常量池

在Class檔案結構中,最頭的4個位元組用於儲存Megic Number,用於確定一個檔案是否能被JVM接受,再接著4個位元組用於儲存版本號,前2個位元組儲存次版本號,後2個儲存主版本號,再接著是用於存放常量的常量池,由於常量的數量是不固定的,所以常量池的入口放置一個U2型別的資料(constant_pool_count)儲存常量池容量計數值。

常量池主要用於存放兩大類常量:字面量(Literal)和符號引用量(Symbolic References),字面量相當於Java語言層面常量的概念,如文字字串,宣告為final的常量值等,符號引用則屬於編譯原理方面的概念,包括瞭如下三種類型的常量:

  • 類和介面的全限定名
  • 欄位名稱和描述符
  • 方法名稱和描述符

三、 常量池的好處

常量池是為了避免頻繁的建立和銷燬物件而影響系統性能,其實現了物件的共享。例如字串常量池,在編譯階段就把所有的字串文字放到一個常量池中。

  • 節省記憶體空間:常量池中所有相同的字串常量被合併,只佔用一個空間。
  • 節省執行時間:比較字串時,==比equals()快。對於兩個引用變數,只用==判斷引用是否相等,也就可以判斷實際值是否相等。

雙等號==的含義

  • 基本資料型別之間應用雙等號,比較的是他們的數值。
  • 複合資料型別(類)之間應用雙等號,比較的是他們在記憶體中的存放地址。

四、 基本型別的包裝類和常量池

java中基本型別的包裝類的大部分都實現了常量池技術,即Byte,Short,Integer,Long,Character,Boolean。這5種包裝類預設建立了數值[-128,127]的相應型別的快取資料,但是超出此範圍仍然會去建立新的物件。 兩種浮點數型別的包裝類Float,Double並沒有實現常量池技術

1)Integer與常量池

複製程式碼 複製程式碼
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);

System.out.println("i1=i2   " + (i1 == i2));
System.out.println("i1=i2+i3   " + (i1 == i2 + i3));
System.out.println("i1=i4   " + (i1 == i4));
System.out.println("i4=i5   " + (i4 == i5));
System.out.println("i4=i5+i6   " + (i4 == i5 + i6));  
System.out.println("40=i5+i6   " + (40 == i5 + i6));


i1=i2   true
i1=i2+i3   true
i1=i4   false
i4=i5   false
i4=i5+i6   true
40=i5+i6   true
複製程式碼 複製程式碼
解釋:
  • Integer i1=40;Java在編譯的時候會直接將程式碼封裝成Integer i1=Integer.valueOf(40);,從而使用常量池中的物件。
  • Integer i1 = new Integer(40);這種情況下會建立新的物件。
  • 語句i4 == i5 + i6,因為+這個操作符不適用於Integer物件,首先i5和i6進行自動拆箱操作,進行數值相加,即i4 == 40。然後Integer物件無法與數值進行直接比較,所以i4自動拆箱轉為int值40,最終這條語句轉為40 == 40進行數值比較。

2)String與常量池-普通方法賦值

複製程式碼 複製程式碼
String str1 = "abcd";
String str2 = new String("abcd");
System.out.println(str1==str2);//false

String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
System.out.println("string" == "str" + "ing");// true System.out.println(str3 == str4);//false String str5 = "string"; System.out.println(str3 == str5);//true
複製程式碼 複製程式碼
解釋:
  • “abcd”是在常量池中拿物件,new String(“abcd”)是直接在堆記憶體空間建立一個新的物件。只要使用new方法,便需要建立新的物件
  • 連線表示式 +,只有使用引號包含文字的方式建立的String物件之間使用“+”連線產生的新物件才會被加入常量池中
  • 對於字串變數的“+”連線表示式,它所產生的新物件都不會被加入字串池中,其屬於在執行時建立的字串,具有獨立的記憶體地址,所以不引用自同一String物件。

3)String與常量池-靜態方法賦值

複製程式碼 複製程式碼
public static final String A; // 常量A
public static final String B;    // 常量B
static {  
   A = "ab";  
   B = "cd";  
}  
public static void main(String[] args) {  
// 將兩個常量用+連線對s進行初始化  
String s = A + B;  
String t = "abcd";  
if (s == t) {  
    System.out.println("s等於t,它們是同一個物件");  
  } else {  
    System.out.println("s不等於t,它們不是同一個物件");  
  }  
}
複製程式碼 複製程式碼
解釋:

s不等於t,它們不是同一個物件。A和B雖然被定義為常量,但是它們都沒有馬上被賦值。在運算出s的值之前,他們何時被賦值,以及被賦予什麼樣的值,都是個變數。因此A和B在被賦值之前,性質類似於一個變數。那麼s就不能在編譯期被確定,而只能在執行時被建立了。

4)String與常量池-intern方法

複製程式碼 複製程式碼
public static void main(String[] args) {
  String s1 = new String("計算機");
  String s2 = s1.intern();
  String s3 = "計算機";
  System.out.println("s1 == s2? " + (s1 == s2));
  System.out.println("s3 == s2? " + (s3 == s2));
}
s1 == s2? false s3 == s2? true
複製程式碼 複製程式碼
解釋:

String的intern()方法會查詢在常量池中是否存在一份equal相等的字串,如果有則返回該字串的引用,如果沒有則新增自己的字串進入常量池

5)String與常量池-延伸

String s1 = new String("xyz"); //建立了幾個物件?
解釋:

考慮類載入階段和實際執行時。

  • 類載入對一個類只會進行一次。”xyz”在類載入時就已經建立並駐留了(如果該類被載入之前已經有”xyz”字串被駐留過則不需要重複建立用於駐留的”xyz”例項)。駐留的字串是放在全域性共享的字串常量池中的。
  • 在這段程式碼後續被執行的時候,”xyz”字面量對應的String例項已經固定了,不會再被重複建立。所以這段程式碼將常量池中的物件複製一份放到heap中,並且把heap中的這個物件的引用交給s1 持有

這條語句建立了2個物件。

相關推薦

jvm虛擬機器 class檔案常量執行常量

jvm虛擬機器 class檔案常量池與執行時常量池 class檔案常量池 java檔案編譯後生成class檔案,裡面存有兩部分內容: 類的版本、欄位、方法、介面等描述資訊。(欄位是指我們平時在介面或類裡宣告的各種變數 int a 等) 常量池:存放編譯期生成的字

常量執行常量

一、執行時常量池簡介 執行時常量池(Runtime Constant Pool),它是方法區的一部分。Class檔案中除了有類的版本、欄位、方法、介面等描述等資訊外,還有一項資訊是常量池(Constant Pool Table),用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類載入後存放到常量池中。

String的intern()方法 執行常量(方法區)

String的intern()方法 與執行時常量池(方法區) 在你看這篇文章時我假設你已經瞭解jvm記憶體 1.String.intern()是一個Native方法,作用是:如果字串常量池存在字串相等(equals() )的字串物件,就返回此常量池中的String物件。否則將Stri

後端---Java中的常量(字串常量、class常量執行常量)

在Java的記憶體分配中,總共3種常量池: 在JDK1.7之前執行時常量池邏輯包含字串常量池存放在方法區, 此時hotspot虛擬機器對方法區的實現為永久代 在JDK1.7 字串常量池被從方法區拿到了堆中, 這裡沒有提到執行時常量池,也就是說字串常量池被單獨拿到堆,執行時常量池剩下

Java虛擬機器的靜態常量執行常量

(靜態)常量池:用於存放編譯器生成的各種字面量和符號引用(符號引用區別於直接引用,後者在class位元組碼檔案被虛擬機器解析之後,符號引用將被替換為直接引用)。 執行時常量池:(靜態)常量池中的內容在類載入(這裡的類載入指class位元組碼檔案經過載入連線初始化的過程)後存放入方法區的執

Java中的常量(字串常量、class常量執行常量)

簡介: 這幾天在看Java虛擬機器方面的知識時,看到了有幾種不同常量池的說法,然後我就去CSDN、部落格園等上找資料,裡面說的內容真是百花齊放,各自爭豔,因此,我好好整理了一下,將我自認為對的理解寫下來與大家共同探討: 在Java的記憶體分配中,總共3種常量

Java 中級 學習筆記 1 JVM的理解以及新生代GC處理流程和常量執行常量、字串常量的理解

寫在最前 從畢業到現在已經過去了差不多一年的時間,工作還算順利,但總是離不開CRUD ,我覺得這樣下去肯定是不行的,溫水煮青蛙,勢必有一天,會昏昏沉沉的迷失在溫水裡。所以,需要將之前學習JAVA 當中一些中高階部分的知識需要進行學習和記錄,並將其整理部落格,一起成長,一起努力。 JVM JAVA虛擬機器在執行

Class常量執行常量、字串常量的一些思考

## Class常量池、執行時常量池、字串常量池 ### class常量池 java程式碼經過編譯之後都成了xxx.class檔案,這是java引以為傲的可移植性的基石。class檔案中,在CAFEBABE、主次版本號之後就是常量池入口了,入口是一個u2型別的資料,也就是佔據2個位元組,用來給常量池的容量

String放入執行常量的時機String.intern()方法解惑

執行時常量池概述 Java執行時常量池中主要存放兩大類常量:字面量和符號引用。字面量比較接近於Java語言層面的常量概念,如文字字串、宣告為final的常量值等。 而符號引用則屬於編譯原理方面的概念,包括了下面三類常量: - 類和介面的全限定名(包名+類

02.字串常量 ? class常量? 執行常量?

java物件建立流程: 簡介: 這幾天在看Java虛擬機器方面的知識時,看到了有幾種不同常量池的說法,然後我就去CSDN、部落格園等上找資料,裡面說的內容真是百花齊放,各自爭豔,因此,我好好整理了一下,將我自認為對的理解寫下來與大家共同探討: 在Java的記憶體分配中,總共3種

JVM 記憶體模型:執行常量

1. 前言 最近研究Java基礎知識。發現Java執行時常量池和String字串有些一些細節的地方,值得我們注意的地方,最為一個Java開發人員對於這種java基本特性和JVM虛擬機器的記憶體模型我們需要去深入研究和掌握。 2. 執行時常量池 執行時常量池存在於方法區中,用於存放

℃江的觀後感 -- Java 虛擬機器的方法區、直接記憶體和執行常量

方法區 我們知道方法區,當然是和方法有關,Java虛擬機器的作用就兩個,儲存、運算。其實我們叫其方法區,說明和儲存東西有關,但是存什麼呢?這塊儲存的是虛擬機器載入的類資訊,常亮,靜態變數和有個就是即使編譯後的程式碼等資料。方法區一般在hotspot被稱為永久代

Java記憶體區域——直接記憶體和執行常量

執行時常量池是屬於方法區的一塊,class檔案中除了有類的版本、欄位、方法、介面等描述資訊以外,還有一項資訊就是常量池,那麼,這個常量池是幹什麼的呢?它就是用來存放編譯期生成的各種字面量以及符號引用,這部分內容將在類載入後,進入方法區的執行時常量池中存放。舉個例子 基本

驗證執行常量在JDK1.7被移到Java堆中

JDK1.6程式碼執行及其結果 /** * VM options:-Xms10M -Xmx20M -XX:PermSize=10M -XX:MaxPermSize=10M -XX:-UseGCOverheadLimit */ public class

JVM執行資料區域 —— 程式計數器、Java虛擬機器棧、本地方法棧、Java堆、方法區、執行常量

java虛擬機器執行時資料區域的概括圖如下所示: 下面將對執行時資料區進行講解 程式計數器 1、說明:程式計數器可以看做是當前執行緒所執行的位元組碼的行號指示器。其實通俗點講就是記錄class檔案執行到哪一行 2、注意的點: (1)因為CPU執

JVM詳解之:執行常量

[toc] # 簡介 JVM在執行的時候會對class檔案進行載入,連結和初始化的過程。class檔案中定義的常量池在JVM載入之後會發生什麼神奇的變化呢?快來看一看吧。 # class檔案中的常量池 之前我們在講class檔案的結構時,提到了每個class檔案都有一個常量池,常量池中存了些什麼東西呢

C#兩種常量型別,readonly(執行常量)const(編譯常量)

C#中有兩種常量型別,分別為readonly(執行時常量)與const(編譯時常量),本文將就這兩種型別的不同特性進行比較並說明各自的適用場景。 工作原理 readonly為執行時常量,程式執行時進行賦值,賦值完成後便無法更改,因此也有人稱其為只讀變數

第三十八天 GIL 程序執行

今日內容: 1.GIL 全域性直譯器鎖 2.Cpython直譯器併發效率驗證 3.執行緒互斥鎖和GIL對比 4.程序池與執行緒池 一.全域性直譯器鎖   1.GIL:全域性直譯器鎖     GIL本質就是一把互斥鎖,是夾在直譯器身上的     統一程序內的所有執行緒都需要先搶到GIL鎖,才能執

執行 技術點 目錄 1. 執行作用: 提升效能 1 2. 使用流程 1 3. 執行執行的監控 jvisual 1 4. 執行緒常用方法 2 5. 執行相關概念 2 5.1. 佇列

 池與執行緒池 技術點   目錄 1. 執行緒池作用:  提升效能 1 2. 使用流程 1 3. 執行緒與執行緒池的監控  jvisual 1 4. 執行緒常用方法 2 5. 執行緒池相關概念 2 5.1. 佇列 &n

Python系列之程序執行

在剛開始學多程序或多執行緒時,我們迫不及待地基於多程序或多執行緒實現併發的套接字通訊,然而這種實現方式的致命缺陷是:服務的開啟的程序數或執行緒數都會隨著併發的客戶端數目地增多而增多,這會對服務端主