java有八種基本數(shù)據(jù)類型分別是关顷,char糊秆、shoat武福、int议双、float、double捉片、long平痰、byte、boolean伍纫。
而它們對應的包裝類也有宗雇,Character、Shoat莹规、Integer赔蒲、Float、Double良漱、Long舞虱、Byte、Boolean母市。
那么他們之間有什么區(qū)別呢矾兜,簡單來說他們是完全不同的概念,前者的java提供的基本數(shù)據(jù)類型患久,注意這里說了是基本數(shù)據(jù)類型椅寺;而后者則是java為它們提供常見處理的工具類浑槽,注意說了是類也就是它們存在著對象。
1.初始化
這里以int和Integer為例舉例說明返帕,當我們初始化一個int和一個Integer并沒有給定他們值時桐玻,前者默認值為0,而后者默認為null(空對象)荆萤。
當我們需要傳入一個參數(shù)時畸冲,對int、Integer的選擇就很重要观腊,如果我們傳入的Intger為null很有可能拋出一個空指針異常使我們的程序蹦掉邑闲;而選擇int時因為有初始值,不會出現(xiàn)Intger出現(xiàn)的問題梧油,但是另一個問題也接踵而來苫耸,
我們不知道傳入的int值的多少,很有可能就會給我們的程序埋了一個隱藏的bug儡陨;對于int還是Integer的選擇我們應該通過現(xiàn)實場景進行選擇褪子。
這里重點說一下,當我們使用MVC模式開發(fā)時骗村,Controller接收參數(shù)如果參數(shù)不存在嫌褪,而參數(shù)是int類型時就會拋出一個參數(shù)不存在異常,而Integer卻不會胚股,只是得到的參數(shù)為null笼痛。
2)自動拆箱,自動裝箱機制
自動拆箱和自動裝箱機制是在JDK1.5引進的一個新機制琅拌,觀察下面的代碼缨伊,為什么會有這樣的結(jié)果產(chǎn)生呢。
Integer a = 34;
int b = 34;
Integer c = b;
int d = a;
System.out.println( a == b);
System.out.println( d == c);
基本數(shù)據(jù)類型的和其包裝類的相互轉(zhuǎn)換进宝,這是為什么呢刻坊?
答案很簡單,因為我們在執(zhí)行Integer a = 34; 代碼時jdk默認執(zhí)行的是Integer a = Integer.valueOf(34);
而我們在執(zhí)行int d = a;時編譯執(zhí)行的卻是int d = a.intValue();
你可能會有疑問党晋,為什么會是這樣谭胚?
這個時候我們就需要打開源碼進行查看尋找答案。
/**
Returns an {@code Integer} instance representing the specified
{@code int} value. If a new {@code Integer} instance is not
required, this method should generally be used in preference to
the constructor {@link #Integer(int)}, as this method is likely
to yield significantly better space and time performance by
caching frequently requested values.
This method will always cache values in the range -128 to 127,
inclusive, and may cache other values outside of this range.
@param i an {@code int} value.
@return an {@code Integer} instance representing {@code i}.
@since 1.5
/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
文檔是這樣說的未玻,返回一個制定int數(shù)值的Integer對象實例灾而,這樣好像還不足以說明什么,那我們要如何證明我們是對的呢深胳?
我們可以查看他的編譯文件绰疤,一切就真相大白了(javac命令)。
public static void main(String[] var0) {
new User();
Integer var2 = Integer.valueOf(34);
byte var3 = 34;
Integer var4 = Integer.valueOf(var3);
int var5 = var2.intValue();
System.out.println(var2.intValue() == var3);
System.out.println(var5 == var4.intValue());
}
這好像就不需要我再多說什么了舞终。
細心的小伙伴會看到文檔里面有這么一句話?This method will always cache values in the range -128 to 127,inclusive, and may cache other values outside of this range.該方法會緩存-128到127之間的值轻庆,這句話又是什么意思呢癣猾。
Integer a = 120;Integer b = 120;Integer c = 300;Integer d = 300;System.out.println( a == b);System.out.println( d == c);這兩句代碼會輸出什么呢,小伙伴們肯定說都是true啊余爆,或者說都是false纷宇。會這樣說的小伙伴不能說你錯了,只能說你對了一半蛾方;是這樣的啊像捶,我們知道==運算符進行運算時,運算符兩邊如果都為基本數(shù)據(jù)類型的話那就直接對數(shù)值進行比較桩砰;但是如果兩邊或者一邊為非基本數(shù)據(jù)類型時拓春,即對象實例,則比較的是他們的內(nèi)存地址(如果為空對象的話則為null)亚隅,這里很明顯兩邊都是對象實例硼莽,所以比較的是內(nèi)存地址。
額煮纵?為什么是這樣呢懂鸵,按我們之前講得理論不是應該都為false才對嘛,因為他們比較的是內(nèi)存地址呀行疏。哈哈匆光,這就是我們之前講到的問題,Integer會緩存-128到127之間的數(shù)值酿联,而這么數(shù)值當然是緩存在一個對象實例里面啦终息,當我們需要使用時又進行取出(準確點來說是拿到的是它的引用),而不在這個范圍內(nèi)的數(shù)值當然都是重新創(chuàng)建實例啦货葬,有興趣的小伙伴可以進去看下源碼采幌。
3) 類型轉(zhuǎn)換
這是包裝類很大的存在原因劲够,試想一下震桶,我們有一個數(shù)值傳遞過來時是String或者說是Object類型,我們要怎么轉(zhuǎn)換成int類型呢征绎?
Integer的ValueOf可以將一個String類型轉(zhuǎn)換成int蹲姐。
使用強制類型轉(zhuǎn)換編譯器會報類型轉(zhuǎn)換異常(String類型無法轉(zhuǎn)換成Integert類型),使用valueof方法則可以通過編譯人柿,運行結(jié)果也是正確的柴墩;那么在試想一下,如果是 String a = "120.0";那會是怎么樣的結(jié)果呢凫岖。
拋出一個異常江咳,不能輸入字符串為“120.0”,a是浮點類型的哥放,那怎么辦歼指,總會有解決方法的爹土。
哎呦,好像行不通踩身,F(xiàn)loat精度比Integer高胀茵,嗯!強轉(zhuǎn)挟阻?
也不行琼娘,好像很絕望。Integer b = Float.valueOf(a).intValue();好像行了附鸽,測試一下脱拼。還真行,什么情況坷备,這個intValue又是個什么方法挪拟。/**
Returns the value of this {@code Float} as an {@code int} after
a narrowing primitive conversion.
@return the {@code float} value represented by this object
converted to type {@code int}
@jls 5.1.3 Narrowing Primitive Conversions
*/
public int intValue() {
return (int)value;
}
什么,居然是個強轉(zhuǎn)击你,搞了半天還是強轉(zhuǎn)玉组,那為啥我們那樣轉(zhuǎn)不行呢,因為我們是類強轉(zhuǎn)丁侄,而它是類型轉(zhuǎn)換惯雳。
挖槽還真可以,說明這就沒錯了鸿摇。
4)內(nèi)存使用
這次那long類型來舉例石景,因為這樣舉例會比較明顯,我們知道long類型是占8個字節(jié)(占用跟系統(tǒng)有關)拙吉,而Long包裝類呢潮孽,卻是一個對象。
Long start = System.currentTimeMillis();
Long l = 0L;
for (Integer i = 0; i < Integer.MAX_VALUE; i++){
l++;
}
System.out.println(System.currentTimeMillis() - start);
這段代碼會執(zhí)行多久呢筷黔,好像是一瞬間的事往史,可是他執(zhí)行了13060ms,可能這關系到機器佛舱,但是這個問題是很嚴重的椎例,如果不小心寫了這樣的代碼,搞蹦一個程序是很簡單的事情请祖。
這里每次執(zhí)行l(wèi)++操作其實都相當于創(chuàng)建了一個新的實例订歪,那這個量就非常大了,而如果換成基本數(shù)據(jù)類型的話肆捕,從始至終它都是8個字節(jié)刷晋。
我們修改一下程序
Long start = System.currentTimeMillis();
long l = 0L;
for (int i = 0; i < Integer.MAX_VALUE; i++){
l++;
}
System.out.println(System.currentTimeMillis() - start);
那么它的運行時間又是多少呢?78ms
是不是很驚訝,相差了好幾百倍眼虱,所以我們絕對不可以出現(xiàn)這樣的代碼或舞,對于基本數(shù)據(jù)類型還是包裝類的選擇,我們首選還是基本數(shù)據(jù)類型蒙幻,而當某些場景無法繼續(xù)使用基本數(shù)據(jù)類型時映凳,我們才使用包裝類進行處理。
OK邮破,到此為止诈豌,基本數(shù)據(jù)類型跟包裝類之間的關系和區(qū)別我就講完了,如果有講的不好或者是講得不對的地方大家一定要指出來抒和,不然我就沒法進步了矫渔!
?都看到這里了點個贊再走唄。