1. 程式人生 > >Java程式設計師面試,自動封箱/拆箱原理與包裝類的緩衝機制你知道麼?

Java程式設計師面試,自動封箱/拆箱原理與包裝類的緩衝機制你知道麼?

概述

本文中小編為大家細緻的講解了Java中基本資料型別對應的包裝類以及包裝類的緩衝機制在實際開發中的應用 。 並且對Java中基本資料型別的包裝類的主要應用---自動封箱、自動拆箱做了底層剖析 。

自JDK1.5開始, 引入了自動裝箱/拆箱這一語法糖, 它使程式設計師的程式碼變得更加簡潔, 不再需要進行顯式轉換。基本型別與包裝型別在某些操作符的作用下, 包裝型別呼叫valueOf()方法將原始型別值轉換成對應的包裝類物件的過程, 稱之為自動裝箱; 反之呼叫xxxValue()方法將包裝類物件轉換成原始型別值的過程, 則稱之為自動拆箱。

一、Java中基本資料型別各自對應的包裝類

詳細的資料型別學習請參閱:資料型別總結

二、Jav中包裝類的實際應用

手動封箱 :

Integer in = new Integer(123); //將一個基本資料型別的值轉換為對應的引用型別的物件。

System.out.println(in);//打印出的是物件的值,而不是地址 --- 底層對toString做過重寫

注意:

字串轉Integer :

Integer in = new Integer("0x23"); //執行報錯:字串底層是以字串陣列形式儲存,在轉換時會一次判斷每一位是不是數字,所以只支援十進位制的數。

數值型的基本資料型別的包裝類都是Number類的子類。

字串轉Boolean:

Boolean b = new Boolean(str); //要求引數是字串,當str="true"時 b值為 true;當str為"false"或任意字串時,b值為false。

自動封箱:

將一個基本資料型別的變數直接賦值給對應引用型別。是JDK1.5的新特性 之一。

底層實現:自動封箱實際上是呼叫了valueOf() --> Integer in = Integer.valueOf(i); valueOf返回一個Integer型別的例項。

/*
* 自動封箱的測試
*/
int i = 1;
int j = 1;
Integer in1 = i;//自動封箱
Integer in2 = Integer.valueOf(i);
System.out.println(in1==in2);//true
System.out.println(in1.equals(in2));//true		                                         
System.out.println(in1.equals(j));//true
//j是一個基本資料型別,在用equals方法進行物件的比較時,j被自動封箱

自動拆箱:

int num1 = 1;
int num2 = 2;
Integer in = num1;
int res = in+num2;//拆箱
System.out.println(res);
//將一個引用型別的例項直接賦值給對應基本資料型別的變數。 JDK1.5的新特性之一。底層實現:實際上是呼叫了****value()方法(xxx指的是對應 的基本資料型別)。---> int i = in.intVlaue(); // ***value() 返回對應基本型別的值。

整數的雜湊碼是自己本身。Integer底層對hashCode()方法做過重寫。

數值型別的雜湊碼是不變的。

注意:

Integer i1 = 123;

Integer i2 = 123;

i1==i2 ;//true;

Integer i3 = 1234;

Integer i4 = 1234;

i3==i4;//false

解釋:int型別的值在常量池中初始化,只初始化-128~127的範圍。所以當值在-128~127中時,是直接從從常量池中取值,而常量池中的常量是被共享的,所以i1==i2;當值 不在-128~127之間時,會new Integer(),所以i3、i4指向的堆記憶體地址 不一樣。

自動拆箱應用:

Integer i1 = new Ingeter(123);

int i = 123;

i1 == i; //true

解釋: 當引用型別與基本型別直接運算時,引用型別會自動拆箱。

三、包裝類的緩衝機制

  • 包裝類同String類相似,也是非可變類,其物件一經建立,就不能修改。並且,包裝類也重寫了equals方法,對於相同型別的兩個包裝類物件,只要兩個物件所包裝的基本資料型別的值是相等的,則equals方法就會返回true,否則返回false。
  • 在使用“==”比較兩個包裝類引用時,如果兩個引用指向的地址相同(指向相同的物件),則結果為true,否則結果為false。 
  • 包裝類提供了物件的快取,具體的實現方式為在類中預先建立頻繁使用的包裝類物件,當需要使用某個包裝類的物件時,如果該物件封裝的值在快取的範圍內,就返回快取的物件,否則建立新的物件並返回。 

在包裝類中,快取的基本資料型別值得範圍如下:

包裝型別 基本資料型別 快取物件(基本資料型別值)
Boolean boolean true,false(全部值)
Byte byte -128~127(全部值)
Short short -128~127
Character char 0~127
Integer int -128~127(預設為127)
Long long -128~127
Float float 無快取值
Double double 無快取值

在jdk1.5及之後的版本中,Java在5大包裝類中(Byte,Charactor,Short,Integer,Long)增加了相應的私有靜態成員內部類為相應包裝類物件提供快取機制,Integer包裝類的內部快取類原始碼如下:

正如原始碼中所指,在自動裝箱的基礎上,快取機制才會發生作用;當包裝類載入時,內部類會初始化一個長度為((high-low)+1)的包裝類型別陣列,low有固定值為-128,而high的預設值為127,還可以通過系統配置檔案進行修改,自定義high的取值範圍是127---------(Interger.MAX_VALUE+127),Integer.MAX_VALUE是int型別變數的最大正數取值;’

其快取機制是:當通過自動裝箱機制建立包裝類物件時,首先會判斷數值是否在-128----127的範圍內,如果滿足條件,則會從快取中尋找指定數值,若找到快取,則不會新建物件,只是指向指定數值對應的包裝類物件,否則,新建物件。

            Integer a = new Integer(100);
            Integer b = new Integer(100);
            System.out.println(a == b);
          // 輸出為false,非自動裝箱機制實現,屬於兩個不同的物件,所以返回false.
//--------------------------------分割線---------------------------------------
                int num1 = 127;
		int num2 = 127;//
		Integer in1 = num1;
		Integer in2 = num2;
		System.out.println(in1 == in2);//true
                //全部都在範圍之內,所以為true
//--------------------------------分割線---------------------------------------
		int num3 = 127;
		int num4 = 128;//超過了上限,成為一個緩衝範圍外的新物件
		Integer in3 = num3;
		Integer in4 = num4;
		System.out.println(in3 == in4);//false
                //num4的包裝類in4超過了上限,成為一個緩衝範圍外的新物件,所以為false

其實,Integer的快取下限固定為-128,而快取上限是可以在執行時通過修改系統屬性來設定的。  比如可以在命令列輸入:

java -Djava.lang.Integer.IntegerCache.high=100 xxx

   或者在選擇server虛擬機器時,輸入:

java -server -XX:AutoBoxCacheMax=100 xxx

       如果去掉-server引數,將報錯,這是因為,預設的虛擬機器是client虛擬機器,也就是不加引數或者使用-client引數時系統選擇的虛擬機器,而client虛擬機器不支援-XX:AutoBoxCacheMax引數。         如果同時使用以上方式來設定快取上限屬性,以-XX:AutoBoxCacheMax引數為準。

後記

感謝各位大神的閱讀 , 如果有錯誤的地方或者是文章剖析的不夠透徹 , 希望您能夠不吝賜教在評論中告訴小編 , 以便小編能 更好的提升文章的質量。如果您還有什麼不明白的地方也可以在評論中與大家一起探討。

每個人都是自己的上帝。如果你自己都放棄自己了,還有誰會救你?------《肖申克的救贖》