JDK8常量池整理


1、常量

字面量包括:1.文本字符串 2.八種基本類型的值 3.被聲明為final的常量等;

符號引用包括:1.類和方法的全限定名 2.字段的名稱和描述符 3.方法的名稱和描述符。

2、常量池分類

類文件常量池:又稱為靜態常量池,存儲區域在堆中,編譯時產生對應的class文件,主要包含字面量和符號引用;

運行時常量池:存在元數據(Meta Space)空間,JVM運行時,在類加載完成后,將每個class常量池中的符號引用轉換為直接引用

字符串常量池:存在堆內存中,類在加載、驗證、准備完成后在堆中生成字符串對象實例,然后將該字符串對象實例的引用只存儲到Sting Pool中,String Pool是一個StringTable類,是哈希表結果,里面存儲的是字符串引用,具體的實例對象存儲在堆中,這個stringtable表在每個hotspot中的實例只有一份,被所有類共享。

基本類型包裝類常量池:

3、運行時常量池

運行時常量池是方法區元數據區的一部分。Class 文件中除了有類的版本、字段、方法、接口等描述信息外,還有常量池表(用於存放編譯期生成的各種字面量和符號引用)。

1、JDK1.7之前版本運行時常量池包含字符串常量池位於方法區。
2、JDK1.7版本字符串常量池位置從方法區搬到了堆中; 運行時常量池還在方法區。
3、JDK1.8hotspot永久代被元空間(Metaspace)取代, 字符串常量池位置還在堆中, 運行時常量池位置變成了元空間(Metaspace)。

4、字符串常量池

 1 package com.javabasic.str;
 2 
 3 public class StringTest1 {
 4 
 5     public static void main(String[] args) {
 6         //對象創建兩種方式
 7         //第一種:創建了幾個對象呢? 1個或2個 第一個對象:如果常量池中已有"abc"直接返回引用,如果不存在就創建一個;第二個對象:在堆內存中new的String對象。
 8         String s1 = new String("abc");//s1指向堆內存對象的引用地址
 9         
10         //第二種:堆內存字符常量池(首先檢查字符串常量池中是否存在,如果存在則直接引用,不存在添加進入)
11         String s2 = "abc";//指向字符串常量池引用
12         String s3 = "abc";//指向字符串常量池引用
13         System.out.println(s1==s2);//false
14         System.out.println(s2==s3);//true
15         System.out.println("1>>>>>>>>>>>>>>>");
16         
17         String s4 = new String("hello");//s4指向堆內存地址的引用地址
18         s4.intern();//調用intern方法,查詢字符常量池是否存在字符串,如果不存在就放入字符常量池,如果存在返回地址引用
19         String s5 = "hello";
20         System.out.println(s4==s5);//false
21         System.out.println("2>>>>>>>>>>>>>>>");
22         
23         //字符串拼接
24         String s6_1 = "123" + "123";//在字符串常量池創建
25         String s6_2 = new String("123") + new String("123");//在對內存中創建
26         String s7 = "123123";
27         System.out.println(s6_1==s6_2);//false
28         System.out.println(s6_1==s7);//true
29         System.out.println(s6_2==s7);//false
30         System.out.println("3>>>>>>>>>>>>>>>");
31         
32         String s8 = new String("456") + "4561";//在字符串常量池創建
33         String s9 = "4564561";
34         System.out.println(s8==s9);//false
35         System.out.println("4>>>>>>>>>>>>>>>");
36         
37         final String s10 = "abc";
38         final String s11 = new String("abc");
39         System.out.println("s1與s7:" + (s1 == s10));// false
40         System.out.println("s1與s8:" + (s1 == s11));// false
41     }
42 
43 }

String.intern() 是一個 Native 方法,它的作用是:

如果運行時常量池中已經包含一個等於此 String 對象內容的字符串,則返回常量池中該字符串的引用

如果沒有,

JDK1.7之前(不包含1.7)的處理方式是在常量池中創建與此 String 內容相同的字符串,並返回常量池中創建的字符串的引用;

JDK1.7以及之后的處理方式是在常量池中記錄此字符串的引用,並返回該引用。

5、基本類型包裝類常量池

Java 基本類型的包裝類的大部分都實現了常量池技術,即 Byte,Short,Integer,Long,Character,Boolean。

前面 4 種包裝類默認創建了數值[-128,127] 的相應類型的緩存數據,

Character創建了數值在[0,127]范圍的緩存數據,

Boolean 直接返回True Or False。

 兩種浮點數類型的包裝類 Float,Double 沒有實現常量池技術。

 1 package com.javabasic.str;
 2 
 3 import java.lang.Integer.IntegerCache;
 4 
 5 /**
 6  * 默認創建了數值[-128,127] 的相應類型的緩存數據
 7  * @author wangymd
 8  *
 9  */
10 public class IntegerTest1 {
11 
12     public static void main(String[] args) {
13         Integer i1 = 40;//Java 在編譯的時候會直接將代碼封裝成 Integer i1=Integer.valueOf(40);,從而使用常量池中的對象。
14         Integer i2 = 40;//常量池
15         Integer i3 = 0;
16         Integer i4 = new Integer(40);//這種情況下會在堆中創建新的對象
17         Integer i5 = new Integer(40);//堆內存
18         Integer i6 = new Integer(0);
19         
20         Integer i7 = i2 + i3;//因為+這個操作符不適用於 Integer 對象,首先 i5 和 i6 進行自動拆箱操作,進行數值相加
21         Integer i8 = i5 + i6;
22         Integer i9 = new Integer(128);
23         Integer i10 = new Integer(128);
24         
25         Integer i11 = Integer.valueOf(127);//IntegerCache.cache取數
26         Integer i12 = Integer.valueOf(127);//IntegerCache.cache取數
27         
28         Integer i13 = Integer.valueOf(128);
29         Integer i14 = Integer.valueOf(128);
30 
31         System.out.println("i1==i2   " + (i1 == i2));//true
32         System.out.println("i1==i7   " + (i1 == i7));//true
33         System.out.println("i1==i4   " + (i1 == i4));//false
34         System.out.println("i4==i5   " + (i4 == i5));//false
35         System.out.println("i4==i8   " + (i4 == i8));//false
36         System.out.println("40==i8   " + (40 == i8));//true Integer對象無法與數值進行直接比較,所以 i4 自動拆箱轉為 int 值 40,最終這條語句轉為 40 == 40 進行數值比較。
37         System.out.println("i9==i10   " + (i9 == i10));//false
38         System.out.println("i11==i12   " + (i11 == i12));//true
39         System.out.println("i13==i14   " + (i13 == i14));//false
40     }
41 
42 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM