漫談java中的常量和常量池

2020-5-2 13:06| 發布者: 123456911| 查看: 85| 評論: 1

摘要: 本篇文章講述了java中的常量和常量池相關內容。歡迎大家關注我。一、相關概念1、什么是常量用final修飾的成員變量表示常量,值一旦給定就無法改變!final修飾的變量有三種:靜態變量、實例變量和局部變量,分別表示 ...

本篇文章講述了java中的常量和常量池相關內容。歡迎大家關注我。

一、相關概念


1、什么是常量

用final修飾的成員變量表示常量,值一旦給定就無法改變!

final修飾的變量有三種:靜態變量、實例變量和局部變量,分別表示三種類型的常量。

2、Class文件中的常量池

在Class文件結構中,最頭的4個字節用于存儲魔數Magic Number,用于確定一個文件是否能被JVM接受,再接著4個字節用于存儲版本號,前2個字節存儲次版本號,后2個存儲主版本號,再接著是用于存放常量的常量池,由于常量的數量是不固定的,所以常量池的入口放置一個U2類型的數據(constant_pool_count)存儲常量池容量計數值。

常量池主要用于存放兩大類常量:字面量(Literal)和符號引用量(Symbolic References),字面量相當于Java語言層面常量的概念,如文本字符串,聲明為final的常量值等,符號引用則屬于編譯原理方面的概念,包括了如下三種類型的常量:
  • 類和接口的全限定名
  • 字段名稱和描述符
  • 方法名稱和描述符

3、方法區中的運行時常量池

運行時常量池是方法區的一部分。

CLass文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后進入方法區的運行時常量池中存放。

運行時常量池相對于CLass文件常量池的另外一個重要特征是具備動態性,Java語言并不要求常量一定只有編譯期才能產生,也就是并非預置入CLass文件中常量池的內容才能進入方法區運行時常量池,運行期間也可能將新的常量放入池中,這種特性被開發人員利用比較多的就是String類的intern()方法。

4、常量池的好處

常量池是為了避免頻繁的創建和銷毀對象而影響系統性能,其實現了對象的共享。

例如字符串常量池,在編譯階段就把所有的字符串文字放到一個常量池中。
  • (1)節省內存空間:常量池中所有相同的字符串常量被合并,只占用一個空間。
  • (2)節省運行時間:比較字符串時,==比equals()快。對于兩個引用變量,只用==判斷引用是否相等,也就可以判斷實際值是否相等。

5、雙等號==的含義

基本數據類型之間應用雙等號,比較的是他們的數值。

復合數據類型(類)之間應用雙等號,比較的是他們在內存中的存放地址。

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


1、常量緩存規則

Integer、Short、Long,Byte對-128~127范圍內的數字,進行了緩存;Boolean對兩個值都有緩存;Character對0~255范圍內的值進行緩存;Float和Double這兩個浮點數包裝類,并沒有常量緩存。

2、應用場景
Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);//輸出false

  • Integer i1=40;Java在編譯的時候會直接將代碼封裝成Integer i1=Integer.valueOf(40);,從而使用常量池中的對象。
  • Integer i1 = new Integer(40);這種情況下會創建新的對象。

三、String類和常量池


1、String對象創建方式
 String str1 = "abcd";
String str2 = new String("abcd");
System.out.println(str1==str2);//false

這兩種不同的創建方法是有差別的,第一種方式是在常量池中拿對象,第二種方式是直接在堆內存空間創建一個新的對象。

只要使用new方法,便需要創建新的對象。

2、連接表達式 +
  • 只有使用引號包含文本的方式創建的String對象之間使用“+”連接產生的新對象才會被加入字符串池中。
  • 對于所有包含new方式新建對象(包括null)的“+”連接表達式,它所產生的新對象都不會被加入字符串池中。

3、String s1 = new String("xyz");**創建了幾個對象? **

考慮類加載階段和實際執行時。
  • 類加載對一個類只會進行一次。"xyz"在類加載時就已經創建并駐留了(如果該類被加載之前已經有"xyz"字符串被駐留過則不需要重復創建用于駐留的"xyz"實例)。駐留的字符串是放在全局共享的字符串常量池中的。
  • 在這段代碼后續被運行的時候,"xyz"字面量對應的String實例已經固定了,不會再被重復創建。所以這段代碼將常量池中的對象復制一份放到heap中,并且把heap中的這個對象的引用交給s1 持有。

這條語句創建了2個對象。

4、java.lang.String.intern()

運行時常量池相對于CLass文件常量池的另外一個重要特征是具備動態性,Java語言并不要求常量一定只有編譯期才能產生,也就是并非預置入CLass文件中常量池的內容才能進入方法區運行時常量池,運行期間也可能將新的常量放入池中,這種特性被開發人員利用比較多的就是String類的intern()方法。

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

作者:夢工廠

鏈接:https://www.jianshu.com/p/c7f47de2ee80

來源:簡書

漫談java中的常量和常量池


路過

雷人

握手

鮮花

雞蛋

相關分類

返回頂部
优酷路由宝为什么可以赚钱吗 下载江西yy麻将 辉煌棋牌新版本 双色球走势图500期图 股票论坛 喜乐彩票App 江西11选5哪里玩 30选5中三个号 芝麻策略 北京快3公交路线 重庆幸运农场杀一码