首頁 >Java >java教程 >Java中常數池是什麼? Java常數池的介紹

Java中常數池是什麼? Java常數池的介紹

不言
不言原創
2018-09-20 14:40:448435瀏覽

本篇文章帶給大家的內容是關於Java中常數池是什麼? Java常數池的介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

Java當中的常數池

在Java虛擬機jvm中,記憶體分佈為:虛擬機堆,程式計數器,本地方法棧,虛擬機棧,方法區。

Java中常數池是什麼? Java常數池的介紹

程式計數器是jvm執行程式的管線,是用來存放一些指令的,本地方法堆疊是jvm作業系統方法所使用的棧,而虛擬機器棧是用來執行程式碼的棧,在方法區中有類變量,類信息,方法信息,常量池(符號的引用,以表的形式存在的),堆是虛擬機執行程序代碼的所用的堆。

常數?是一旦給定了值就無法改變的量,用final修飾的成員變數為常數。

什麼是class檔案常數池?

我們知道在class檔案中,有類別的版本訊息,欄位訊息,方法,介面等訊息,還有一個就是常數池, 這個就是class檔案常數池了。

class檔案常數池主要用來存放的是什麼呢?

儲存的是編譯產生的各種字面量和符號參考。在計算機科學中,字面量是用來表達原始碼中固定值的表示法;而符號引用是一組符號用來描述所引用的目標,可以是任何形式的字面量,只要使用時能夠無歧義的定位到目標就行。

常數池是以表的形式存在(表是用來儲存字串值的,不儲存符號參考),實際上可以分兩種,一種為靜態常數池,另一種為運行時常量池,共有11中常量表,常量池的每一個常數代表一張表。

常數量表

##CONSTANT_NameAndType12對一個欄位或方法的部分符號引用

常數池

Integer integer1 = 127;
Integer integer2 = 127;
System.out.println(integer1 == integer2);
// true
Integer integer1 = 128;
Integer integer2 = 128;
System.out.println(integer1 == integer2);
// false

在Java中符號「==」是用來比較位址,符號「equals」預設是與符號「==」一樣,都是用來比較位址的。

String string1 = "dashu";
String string2 = "dashu";
System.out.println(string1==string2);
// true
String string1 = "dashu";
String string3 = new String("dashu");
System.out.println(string1 == string3);
// false

String str = new String("dashu"); 建立了幾個物件呢?
答案是:2個或1個。

在new String("dashu");,如果這個「dashu」字面值已經出現在常數池中,那麼就只出創建一個對象,如果沒有就創建兩個對象。

原理: 出現了字面量“dashu”,系統會到字串常數池中查找是否有相同的字串存在,如果有,就不會創建新的物件了,否則就會用字面量值“dashu”,建立一個String物件。而new String("dashu"),有關鍵字new的存在,就表示它一定會建立一個新的對象,然後呼叫接收String參數的建構器來初始化。

如果改為string1 == string3.intern()結果為true,因為傳回的是常數池裡面字面值的位址。

堆疊:執行緒堆疊與本機方法堆疊

// 源码
public class Object{
 private static native void registerNatives();
 static{
  registerNatives();
 }
}
// 源码
public boolean equals(Object obj){
 return (this == obj);
}
// 源码
public String toString(){
 return getClass().getName() + "@" + Integer.toHexString(hasCode());
}
// 源码
protected native Object clone() throws CloneNotSupportedException;

native修飾符修飾的是透過JNI來呼叫c語言或是c 執行的。

所有的類別都是Object的子類別。

万物皆对象
// 源码注解
Class {@code Object} is the root of the  class hierarchy.
Every class has {@code Object} as a superclass.
All objects, including arrays, implements the methods of this class.
@ see java.lang Class
@ since JDK1.0

常數池:
Class檔案中儲存所有常數
在Java中說過常數池可以分成兩種形態,靜態常數池和運行時常數池。

靜態常數池就是class檔案中的常數池有字串字面量,類別訊息,方法的資訊等,佔用了class檔案較大部分的空間,在常數池中主要存放的是字面量和符號引用量。

運行時常數池是java虛擬機器在完成類別載入後的操作,將class檔案中的常數池載入到記憶體中,並保證在方法區,我們口中的常數池是在方法區中運作的常數池,運行時常數池具有動態性,在運作期間也能產生新的常數放入池中,就是上方寫過的程式碼。常量不一定要在編譯期間產生,也可以在運作期間產生新的產量放入池中。

如下解析:

Java虛擬機器jvm在執行某個類別的時候,要經過類別從載入到記憶體中,到卸載為止。

整個過程為 加載,驗證,準備,解析,初始化,使用,卸載。

加載,

驗證,class檔案的版本是否能相容於目前的Java虛擬機器版本,然後class檔案要滿足虛擬機器的規格。

準備,需要準備什麼呢?
就是要進行類別成員的初始化為初始值,其中為final修飾的類別變數除外,final變數就直接初始化為變數值,而類別成員不一樣。

解析,什麼是解析呢?
就是把符號引用解析為直接引用,就是我們變數xxx,這種代表變成直接引用,什麼是直接引用呢?就是記憶體位址,如我們常見的xxx0203r0e,這種。

初始化,把關於static修飾的變數或是static靜態程式碼區塊依照順序組成建構器來初始化變數。

使用,

卸載

當類別載入到記憶體後,jvm會將class常數池中的內容存放到運行時常數池中,所以執行時間常數池每個類別都有一個的。

class常數池是存放字面量和符號的引用,是物件的符號引用值,經過解析就是把符號引用解析為直接引用,在編譯階段存放的是常數的符號引用,進行解析後就是直接引用了。然後在全域常數池中保證每個jvm只有一份,存放的是字串常數的直接引用值。

如果改為`string1 == string3.intern()`結果為true,因為傳回的是常數池裡面字面值的位址。

String類別的intern()方法,會在常數池中尋找是否有一份equal()相等的字串。

String string1 = "dashu";
String string3 =  new String("dashu");
System.out.println(string1==string3.intern());

如果常數池中沒有這個“dashu”字面量,那麼就先把這個字面量“dashu”值,先放入到常數之後,再返回常量表的地址。

常數池優點

常數池可以避免因頻繁的創建和銷毀對象,從而導致系統性能的降低,也實現了對象的共享,即可以節省內存空間,也可以節省運轉的時間。

常數量表類型 #標誌值 描述
CONSTANT_Utf8 1 UTF-8編碼的Unicode字串
CONSTANT_Integer 3 int類型的字面值
CONSTANT_Float 4 float類型的字面值
#CONSTANT_Long 5 long類型的字面值
CONSTANT_Double 6 # double類型的字面值
CONSTANT_Class 7 對一個類別或是介面的符號引用
CONSTANT_String 8 String類型的字面值的參考
CONSTANT_Fieldref 9 #對一個欄位的符號
CONSTANT_Methodref 10 對一個類別中方法的符號套用
# CONSTANT_InterfaceMethodref 11 對一個介面中方法的符號引用

以上是Java中常數池是什麼? Java常數池的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn