參考:深刻剖析Java中的裝箱和拆箱;
Java中基本數據類型和包裝類互轉中 緩衝機制的使用 ;
java學習筆記:裝箱和拆箱,包裝器和緩衝池
Java 各 類型數據在內存中分配狀況詳解html
這裏只是在網上找的一些資料;
Java 中的數據類型分爲
1. 基本類型(原始數據類型) byte short int long float double char boolean
基本類型的變量持有原始值。
2. 符合數據類型(引用類型),引用類型持有引用值(即對某個對象的引用,而非對象自己)。java
通常Java在內存分配時會涉及到如下區域:
1. 寄存器:咱們在程序中沒法控制
2. 棧:存放基本類型的數據和對象的引用,但對象自己不存放在棧中,而是存放在堆中
3. 堆:存放用new產生的數據
4. 靜態域:存放在對象中用static定義的靜態成員
5. 常量池:存放常量
6. 非RAM存儲:硬盤等永久存儲空間
其中主要是堆,棧的存儲。數組
函數中定義的一些基本類型的數據變量和對象的引用變量都在函數的棧內存中分配。
棧的優點是存取速度比堆要快,僅次於直接位於CPU 的寄存器,並且數據能夠共享。可是存在棧中的數據大小與生存週期必須是肯定的。
當在一段代碼塊定義一個變量時,Java就在棧中 爲這個變量分配內存空間,當該變量退出該做用域後,Java會自動釋放掉爲該變量所分配的內存空間,該內存空間能夠當即被另做他用。緩存
堆內存用來存放由new建立的對象和數組。 在堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理。
在堆中產生了一個數組或對象後,還能夠 在棧中定義一個特殊的變量,讓棧中這個變量的取值等於數組或對象在堆內存中的首地址,棧中的這個變量就成了數組或對象的引用變量。
引用變量是普通的變量,定義時在棧中分配,引用變量在程序運行到其做用域以外後被釋放。而數組和對象自己在堆中分配,即便程序 運行到使用 new 產生數組或者對象的語句所在的代碼塊以外,數組和對象自己佔據的內存不會被釋放,數組和對象在沒有引用變量指向它的時候,才變爲垃圾,不能在被使用,但仍 然佔據內存空間不放,在隨後的一個不肯定的時間被垃圾回收器收走(釋放掉)。函數
這種類型是經過諸如 int a=7; 的形式來定義的,稱爲自動變量。這裏自動變量是字面值。不是類的實例,即不是類的引用,這裏並無類的存在。a 是指向一個 int 類型的引用,指向 7 這個字面值。因爲其大小肯定生存期可知(這些定義在某個程序塊中,程序塊退出後,字段值就消失),所以存在棧中.
因爲棧的數據能夠共享,所以 int a=3; int b=3;
這段代碼,編譯器首先處理 int a =3;
,先會在棧中建立一個變量爲 a 的引用,而後查找有沒有字面值爲 3的地址,沒有找到,就開闢一個存放 3 這個字面值的地址,而後將a 指向 3 的地址。接下來處理int b =3;
在建立完 b 這個引用變量後,因爲棧中已經有 3 這個字面值,便將 b 指向 3 的地址。【定義變量,給變量賦值】性能
Java中的基本類型不是面向對象的,它們只是純粹的數據,除了數值自己的信息以外,基本類型數據不帶有其餘信息或者可操做方法。這在實際使用中存在不少不足,爲了解決這個不足,* 對每一個基本類型都對應了一個引用的類型*,稱爲裝箱基本類型。
學習
裝箱:根據數據建立對應的包裝對象。優化
Integer i = new Integer (3); Integer j = 4;//jdk1.5 以後能夠經過這種方式自動裝箱
拆箱:將包裝類型轉換爲基本數據類型。ui
int index2 = j.intValue(); int index1 = i;//自動拆箱
JDK1.5 爲Integer 增長了一個全新的方法:public static Integer valueOf(int i)
在自動裝箱過程時,編譯器調用的是static Integer valueOf(int i)這個方法 因而Integer a=3;
==> Integer a=Integer.valueOf(3);
。spa
此方法與new Integer(i)的不一樣處在於:
方法一調用類方法返回一個表示 指定的 int 值的 Integer 實例。方法二產生一個新的Integer 對象。
JDK API文檔中對這個新的valueOf方法有明確的解釋:
若是不須要新的 Integer 實例,則一般應優先使用該方法,而不是構造方法 Integer(int),由於該方法有可能經過緩存常常請求的值而顯著提升空間和時間性能 .
查看Integer的valueOf方法的:
public static Integer valueOf(int i) { assert IntegerCache.high >= 127; //static final int low = -128; //當-128=<i<=127的時候,就直接在緩存中取出 i de Integer 類型對象 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; //不然就在堆內存中建立 return new Integer(i); }
看出對於範圍 [-128,127] 的整數,valueOf 方法作了特殊處理。採用IntegerCache.cache[i + (-IntegerCache.low)];
這個方法。
查看 IntegerCache 類的實現爲:
private static class IntegerCache { static final int low = -128; //最小值是固定的 static final int high; static final Integer cache[];//cache 緩存是一個存放Integer類型的數組 static { //初始化,最大值能夠配置 // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } high = h; cache = new Integer[(high - low) + 1]; //初始化數組 int j = low; //緩存區間數據 for(int k = 0; k < cache.length; k++) //將-128~127包裝成256個對象存入緩存 cache[k] = new Integer(j++); } private IntegerCache() {} }
IntegerCache初始化後內存中就有Integer緩衝區cache[]了,-128~127區間的int值有其對應的的包裝對象。這就是 valueOf 方法真正的優化方法,當-128=
public class ZhuangXaing {
public static void main(String[] args) {
Integer i= new Integer(12); Integer j=12; Integer k=Integer.valueOf(12); Integer l= new Integer(232); Integer m=232; Integer n=232; Double q = 232.0; System.out.println("use ==......."); System.out.println(i==12); System.out.println(i==j); System.out.println(j==k); System.out.println(l==232); System.out.println(l==m); System.out.println(m==n); System.out.println("use equals....."); System.out.println(m.equals(n)); System.out.println(m.equals(q)); } }
輸出結果:
use ==....... true false true true false false use equals..... true false
Integer i= new Integer(12);
是指明瞭在堆內存中建立對象; Integer j=12;
是自動裝箱,調用valueOf 方法,返回return IntegerCache.cache[12 + 128]
, 獲得的是Integer 緩衝池中的對象。Integer k=Integer.valueOf(12);
與Integer j=12;
本質上相同,指向緩衝池中同一對象。包裝對象與數值比較,自動拆箱。
而對於大於127 的數值,執行的都是return new Integer(i)
都在堆內存中,可是地址不一樣。
對於equals 方法比較的是數值大小:
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
能夠看出比較的 obj 若是是 Integer 的實例,則比較拆箱後數值的是否相等。不然返回false。
2,下面這段代碼輸出結果是什麼:
public class Main { public static void main(String[] args) { Double i1 = 100.0; Double i2 = 100.0; Double i3 = 200.0; Double i4 = 200.0; System.out.println(i1==i2); System.out.println(i3==i4); } //false //false
由於Double類的valueOf方法會採用與Integer類的valueOf方法不一樣的實現。很簡單:在某個範圍內的整型數值的個數是有限的,而浮點數卻不是。
其餘的包裝器:
Boolean: (所有緩存)
Byte: (所有緩存)
Character ( <=127 緩存)
Short (-128~127 緩存)
Long (-128~127 緩存)
Float (沒有緩存)
Doulbe (沒有緩存)
3,下面這段代碼輸出結果是什麼:
public class Main { public static void main(String[] args) { Boolean i1 = false; Boolean i2 = false; Boolean i3 = true; Boolean i4 = true; System.out.println(i1==i2); System.out.println(i3==i4); } }
先看Boolean 類的源碼 ,valueOf 方法的實現:
public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }
而其中的 TRUE 和FALSE又是什麼呢?在Boolean中定義了2個靜態成員屬性:
public static final Boolean TRUE = new Boolean(true); /** * The <code>Boolean</code> object corresponding to the primitive * value <code>false</code>. */ public static final Boolean FALSE = new Boolean(false);
由此可知上面代碼輸出都爲true .