一、Java資料型別
1、在說裝箱與拆箱之前,先說一下Java的基本資料型別,Java從資料型別上可以劃分為值型別
與引用型別
,值型別是四類八種
,分別是:
- 整數型:byte̵,short̵,int̵,long
- 浮點型:float,double
- 字元型:char
- 布林型:boolean
資料型別 | 記憶體 | 預設值 | 包裝類 |
---|---|---|---|
byte | 8位 | 0 | Byte |
short | 16位 | 0 | short |
int | 32位 | 0 | Integer |
long | 64位 | 0L或0l | Long |
float | 32位 | 0.0F或0.0f | Float |
double | 64位 | 0.0D或0.0d | Double |
char | 16位 | \u0000 | Character |
boolean | 8位 | flase | Boolean |
2、引用型別:
- 陣列
- 類(class)
- 介面(Interface)
- 列舉(enum)
3、值型別與引用型別的區別
- 從概念方面上來說:
- 值型別:變數名指向具體的值
- 引用型別:變數名指向資料物件的記憶體地址
- 從記憶體構建方面上來說:
- 值型別:變數在宣告之後,Java就會立刻分配給它記憶體空間
- 引用型別:它以特殊的方式(類似C指標)指向物件實體,這類變數宣告時不會分配記憶體,只是儲存
- 從使用方面上來說:
- 值型別:使用時需要賦具體值,判斷時用 ” == “號
- 引用型別:使用時可以賦null,判斷時使用 equals 方法
二、Java資料型別轉換
1、自動轉換
-
定義:程式在執行過程中“悄然”進行的轉換,不需要使用者提前宣告,一般是從位數低的型別向位數高的型別轉換
-
優先關係:按從低到高的順序轉換。不同型別資料間的優先
關係如下:
- 低--------------------------------------------->高
- byte,short,char-> int -> long -> float -> double
-
轉換規則:
運算中,不同型別的資料先轉化為同一型別,然後進行運算
運算元1型別 運算元2型別 轉換後的型別 byte、short、char int int byte、short、char、int long long byte、short、char、int、long float float byte、short、char、int、long、float double double
2、強制轉換
-
定義:強制型別轉換則必須在程式碼中宣告,轉換順序不受限制
-
格式:在需要轉型的資料前加上“( )”,然後在括號內加入需要轉化的資料型別
-
結果:精度可能會丟失,也可能更加精確
int x; double y; x = (int)3.14 + (int)5.20 //精度丟失 y = (double)x + (double)8 //精度提升 輸出:x = 8;y = 16.0
三、Java之裝箱與拆箱
1、包裝類
- Java是面嚮物件語言,號稱萬事萬物皆物件,因此,8種基本資料型別有了對應的類,這就是包裝類
2、什麼是裝箱與拆箱
-
裝箱:將值型別裝換成引用型別的過程
-
拆箱:將引用型別轉換成值型別的過程
-
自動裝箱:
int x = 3; Integer y = x; //int --> Integer,Integer y = x <==> Integer y = Integer.valueOf(x)
-
自動拆箱:
Integer x = new Integer(5); int y = x; //Integer --> int,int y = x <==> int y = x.intValue()
3、裝箱和拆箱是如何實現的
- 裝箱過程是通過呼叫包裝器的valueOf方法實現的
- 拆箱過程是通過呼叫包裝器的 xxxValue方法實現的。(xxx代表對應的基本資料型別)
4、注意點:
-
大量使用自動拆裝箱會使效能降低,還會造成大量的記憶體消耗
-
在過載方法中,可能出現問題
List<Integer> list = new ArrayList<>(); Integer x,y,z; x = 1;y = 2;z = 4; list.add(x);list.add(y);list.add(z); list.remove(2);
在上面這段程式碼中ArrayList.remove方法有兩個過載方法,那麼list.remove(2)是呼叫了哪個方法,remove掉的是值為2的物件,還是remove了index為2,值為4的那個物件呢?
在這種情況下,編譯器不會進行自動拆裝箱,所以呼叫的是remove(int index),index為2值為4的這個Integer物件會被remove.
如果要呼叫 remove(Object o)的方法,應該這麼寫 list.remove(y)
-
快取值問題
-
案例解析:
Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200; System.out.println(i1==i2); System.out.println(i3==i4); Output: true false
-
觀察原始碼:
Intteger.valueOf方法
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
IntegerCache類
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; 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) { try { 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); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
從原始碼可以看出,在通過valueOf方法建立Integer物件的時候,如果數值在[-128,127]之間,便返回指向IntegerCache.cache中已經存在的物件的引用;否則建立一個新的Integer物件
-
Byte、Short、Integer、Long四種包裝類預設建立了數值為[-128,127]的相應型別的快取資料,但是超出此範圍仍會建立新的物件。
-
Character預設會建立[0,127]的響應型別的快取資料
-
兩種浮點型沒有實現常量池技術,在某個範圍內的整型數值的個數是有限的,而浮點數卻不是
包裝類 常量池 常量池範圍 Byte 存在 [-128,127] Short 存在 [-128,127] Integer 存在 [-128,127] Long 存在 [-128,127] Character 存在 [0,127] Float 不存在 無 Double 不存在 無 -
注意點:
- 當 "=="運算子的兩個運算元都是 包裝器型別的引用,則是比較指向的是否是同一個物件,而如果其中有一個運算元是表示式(即包含算術運算)則比較的是數值(即會觸發自動拆箱的過程)
- 對於包裝器型別,equals方法並不會進行型別轉換
- 算術運算會觸發裝箱與拆箱過程
文章為原創,轉載請宣告出處