偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

一文讀懂什么是Java中的自動(dòng)拆裝箱

開(kāi)發(fā) 開(kāi)發(fā)工具
本文主要介紹Java中的自動(dòng)拆箱與自動(dòng)裝箱的有關(guān)知識(shí)。基本類型,或者叫做內(nèi)置類型,是Java中不同于類(Class)的特殊類型。它們是我們編程中使用最頻繁的類型。

 本文主要介紹Java中的自動(dòng)拆箱與自動(dòng)裝箱的有關(guān)知識(shí)。

[[242664]]

基本數(shù)據(jù)類型

基本類型,或者叫做內(nèi)置類型,是Java中不同于類(Class)的特殊類型。它們是我們編程中使用最頻繁的類型。

Java是一種強(qiáng)類型語(yǔ)言,***次申明變量必須說(shuō)明數(shù)據(jù)類型,***次變量賦值稱為變量的初始化。

Java基本類型共有八種,基本類型可以分為三類:

  • 字符類型char
  • 布爾類型boolean
  • 整數(shù)類型byte、short、int、long
  • 浮點(diǎn)數(shù)類型float、double。

Java中的數(shù)值類型不存在無(wú)符號(hào)的,它們的取值范圍是固定的,不會(huì)隨著機(jī)器硬件環(huán)境或者操作系統(tǒng)的改變而改變。

實(shí)際上,Java中還存在另外一種基本類型void,它也有對(duì)應(yīng)的包裝類 java.lang.Void,不過(guò)我們無(wú)法直接對(duì)它們進(jìn)行操作。

基本數(shù)據(jù)類型有什么好處

我們都知道在Java語(yǔ)言中,new一個(gè)對(duì)象是存儲(chǔ)在堆里的,我們通過(guò)棧中的引用來(lái)使用這些對(duì)象;所以,對(duì)象本身來(lái)說(shuō)是比較消耗資源的。

對(duì)于經(jīng)常用到的類型,如int等,如果我們每次使用這種變量的時(shí)候都需要new一個(gè)Java對(duì)象的話,就會(huì)比較笨重。

所以,和C++一樣,Java提供了基本數(shù)據(jù)類型,這種數(shù)據(jù)的變量不需要使用new創(chuàng)建,他們不會(huì)在堆上創(chuàng)建,而是直接在棧內(nèi)存中存儲(chǔ),因此會(huì)更加高效。

整型的取值范圍

Java中的整型主要包含byte、short、int和long這四種,表示的數(shù)字范圍也是從小到大的,之所以表示范圍不同主要和他們存儲(chǔ)數(shù)據(jù)時(shí)所占的字節(jié)數(shù)有關(guān)。

先來(lái)個(gè)簡(jiǎn)答的科普,1字節(jié)=8位(bit)。java中的整型屬于有符號(hào)數(shù)。

先來(lái)看計(jì)算中8bit可以表示的數(shù)字:

  1. 最小值:10000000 (-128)(-2^7) 
  2. ***值:01111111(127)(2^7-1) 

整型的這幾個(gè)類型中,

  • byte:byte用1個(gè)字節(jié)來(lái)存儲(chǔ),范圍為-128(-2^7)到127(2^7-1),在變量初始化的時(shí)候,byte類型的默認(rèn)值為0。
  • short:short用2個(gè)字節(jié)存儲(chǔ),范圍為-32,768 (-2^15)到32,767 (2^15-1),在變量初始化的時(shí)候,short類型的默認(rèn)值為0,一般情況下,因?yàn)镴ava本身轉(zhuǎn)型的原因,可以直接寫(xiě)為0。
  • int:int用4個(gè)字節(jié)存儲(chǔ),范圍為-2,147,483,648 (-2^31)到2,147,483,647 (2^31-1),在變量初始化的時(shí)候,int類型的默認(rèn)值為0。
  • long:long用8個(gè)字節(jié)存儲(chǔ),范圍為-9,223,372,036,854,775,808 (-2^63)到9,223,372,036, 854,775,807 (2^63-1),在變量初始化的時(shí)候,long類型的默認(rèn)值為0L或0l,也可直接寫(xiě)為0。

超出范圍怎么辦

上面說(shuō)過(guò)了,整型中,每個(gè)類型都有一定的表示范圍,但是,在程序中有些計(jì)算會(huì)導(dǎo)致超出表示范圍,即溢出。如以下代碼:

  1. int i = Integer.MAX_VALUE; 
  2. int j = Integer.MAX_VALUE; 
  3.  
  4. int k = i + j; 
  5. System.out.println("i (" + i + ") + j (" + j + ") = k (" + k + ")"); 

輸出結(jié)果:i (2147483647) + j (2147483647) = k (-2)

這就是發(fā)生了溢出,溢出的時(shí)候并不會(huì)拋異常,也沒(méi)有任何提示。所以,在程序中,使用同類型的數(shù)據(jù)進(jìn)行運(yùn)算的時(shí)候,一定要注意數(shù)據(jù)溢出的問(wèn)題。

包裝類型

Java語(yǔ)言是一個(gè)面向?qū)ο蟮恼Z(yǔ)言,但是Java中的基本數(shù)據(jù)類型卻是不面向?qū)ο蟮?,這在實(shí)際使用時(shí)存在很多的不便,為了解決這個(gè)不足,在設(shè)計(jì)類時(shí)為每個(gè)基本數(shù)據(jù)類型設(shè)計(jì)了一個(gè)對(duì)應(yīng)的類進(jìn)行代表,這樣八個(gè)和基本數(shù)據(jù)類型對(duì)應(yīng)的類統(tǒng)稱為包裝類(Wrapper Class)。

包裝類均位于java.lang包,包裝類和基本數(shù)據(jù)類型的對(duì)應(yīng)關(guān)系如下表所示

在這八個(gè)類名中,除了Integer和Character類以后,其它六個(gè)類的類名和基本數(shù)據(jù)類型一致,只是類名的***個(gè)字母大寫(xiě)即可。

為什么需要包裝類

很多人會(huì)有疑問(wèn),既然Java中為了提高效率,提供了八種基本數(shù)據(jù)類型,為什么還要提供包裝類呢?

這個(gè)問(wèn)題,其實(shí)前面已經(jīng)有了答案,因?yàn)镴ava是一種面向?qū)ο笳Z(yǔ)言,很多地方都需要使用對(duì)象而不是基本數(shù)據(jù)類型。比如,在集合類中,我們是無(wú)法將int 、double等類型放進(jìn)去的。因?yàn)榧系娜萜饕笤厥荗bject類型。

為了讓基本類型也具有對(duì)象的特征,就出現(xiàn)了包裝類型,它相當(dāng)于將基本類型“包裝起來(lái)”,使得它具有了對(duì)象的性質(zhì),并且為其添加了屬性和方法,豐富了基本類型的操作。

拆箱與裝箱

那么,有了基本數(shù)據(jù)類型和包裝類,肯定有些時(shí)候要在他們之間進(jìn)行轉(zhuǎn)換。比如把一個(gè)基本數(shù)據(jù)類型的int轉(zhuǎn)換成一個(gè)包裝類型的Integer對(duì)象。

我們認(rèn)為包裝類是對(duì)基本類型的包裝,所以,把基本數(shù)據(jù)類型轉(zhuǎn)換成包裝類的過(guò)程就是打包裝,英文對(duì)應(yīng)于boxing,中文翻譯為裝箱。

反之,把包裝類轉(zhuǎn)換成基本數(shù)據(jù)類型的過(guò)程就是拆包裝,英文對(duì)應(yīng)于unboxing,中文翻譯為拆箱。

在Java SE5之前,要進(jìn)行裝箱,可以通過(guò)以下代碼:

  1. Integer i = new Integer(10); 

自動(dòng)拆箱與自動(dòng)裝箱

在Java SE5中,為了減少開(kāi)發(fā)人員的工作,Java提供了自動(dòng)拆箱與自動(dòng)裝箱功能。

自動(dòng)裝箱: 就是將基本數(shù)據(jù)類型自動(dòng)轉(zhuǎn)換成對(duì)應(yīng)的包裝類。

自動(dòng)拆箱:就是將包裝類自動(dòng)轉(zhuǎn)換成對(duì)應(yīng)的基本數(shù)據(jù)類型。

  1. Integer i =10;  //自動(dòng)裝箱 
  2. int b= i;     //自動(dòng)拆箱 

Integer i=10 可以替代 Integer i = new Integer(10);,這就是因?yàn)镴ava幫我們提供了自動(dòng)裝箱的功能,不需要開(kāi)發(fā)者手動(dòng)去new一個(gè)Integer對(duì)象。

自動(dòng)裝箱與自動(dòng)拆箱的實(shí)現(xiàn)原理

既然Java提供了自動(dòng)拆裝箱的能力,那么,我們就來(lái)看一下,到底是什么原理,Java是如何實(shí)現(xiàn)的自動(dòng)拆裝箱功能。

我們有以下自動(dòng)拆裝箱的代碼:

  1. public static  void main(String[]args){ 
  2.     Integer integer=1; //裝箱 
  3.     int i=integer; //拆箱 

對(duì)以上代碼進(jìn)行反編譯后可以得到以下代碼:

  1. public static  void main(String[]args){ 
  2.     Integer integer=Integer.valueOf(1);  
  3.     int i=integer.intValue();  

從上面反編譯后的代碼可以看出,int的自動(dòng)裝箱都是通過(guò)Integer.valueOf()方法來(lái)實(shí)現(xiàn)的,Integer的自動(dòng)拆箱都是通過(guò)integer.intValue來(lái)實(shí)現(xiàn)的。如果讀者感興趣,可以試著將八種類型都反編譯一遍 ,你會(huì)發(fā)現(xiàn)以下規(guī)律:

自動(dòng)裝箱都是通過(guò)包裝類的valueOf()方法來(lái)實(shí)現(xiàn)的.自動(dòng)拆箱都是通過(guò)包裝類對(duì)象的xxxValue()來(lái)實(shí)現(xiàn)的。

哪些地方會(huì)自動(dòng)拆裝箱

我們了解過(guò)原理之后,在來(lái)看一下,什么情況下,Java會(huì)幫我們進(jìn)行自動(dòng)拆裝箱。前面提到的變量的初始化和賦值的場(chǎng)景就不介紹了,那是最簡(jiǎn)單的也最容易理解的。

我們主要來(lái)看一下,那些可能被忽略的場(chǎng)景。

場(chǎng)景一、將基本數(shù)據(jù)類型放入集合類

我們知道,Java中的集合類只能接收對(duì)象類型,那么以下代碼為什么會(huì)不報(bào)錯(cuò)呢?

  1. List<Integer> li = new ArrayList<>(); 
  2. for (int i = 1; i < 50; i ++){ 
  3.     li.add(i); 

將上面代碼進(jìn)行反編譯,可以得到以下代碼:

  1. List<Integer> li = new ArrayList<>(); 
  2. for (int i = 1; i < 50; i += 2){ 
  3.     li.add(Integer.valueOf(i)); 

以上,我們可以得出結(jié)論,當(dāng)我們把基本數(shù)據(jù)類型放入集合類中的時(shí)候,會(huì)進(jìn)行自動(dòng)裝箱。

場(chǎng)景二、包裝類型和基本類型的大小比較

有沒(méi)有人想過(guò),當(dāng)我們對(duì)Integer對(duì)象與基本類型進(jìn)行大小比較的時(shí)候,實(shí)際上比較的是什么內(nèi)容呢?看以下代碼:

  1. Integer a=1; 
  2. System.out.println(a==1?"等于":"不等于"); 
  3. Boolean bool=false
  4. System.out.println(bool?"真":"假"); 

對(duì)以上代碼進(jìn)行反編譯,得到以下代碼:

  1. Integer a=1; 
  2. System.out.println(a.intValue()==1?"等于":"不等于"); 
  3. Boolean bool=false
  4. System.out.println(bool.booleanValue?"真":"假"); 

可以看到,包裝類與基本數(shù)據(jù)類型進(jìn)行比較運(yùn)算,是先將包裝類進(jìn)行拆箱成基本數(shù)據(jù)類型,然后進(jìn)行比較的。

場(chǎng)景三、包裝類型的運(yùn)算

有沒(méi)有人想過(guò),當(dāng)我們對(duì)Integer對(duì)象進(jìn)行四則運(yùn)算的時(shí)候,是如何進(jìn)行的呢?看以下代碼:

  1. Integer i = 10; 
  2. Integer j = 20; 
  3.  
  4. System.out.println(i+j); 

反編譯后代碼如下:

  1. Integer i = Integer.valueOf(10); 
  2. Integer j = Integer.valueOf(20); 
  3. System.out.println(i.intValue() + j.intValue()); 

我們發(fā)現(xiàn),兩個(gè)包裝類型之間的運(yùn)算,會(huì)被自動(dòng)拆箱成基本類型進(jìn)行。

場(chǎng)景四、三目運(yùn)算符的使用

這是很多人不知道的一個(gè)場(chǎng)景,作者也是一次線上的血淋淋的Bug發(fā)生后才了解到的一種案例??匆粋€(gè)簡(jiǎn)單的三目運(yùn)算符的代碼:

  1. boolean flag = true
  2. Integer i = 0; 
  3. int j = 1; 
  4. int k = flag ? i : j; 

很多人不知道,其實(shí)在int k = flag ? i : j;這一行,會(huì)發(fā)生自動(dòng)拆箱。反編譯后代碼如下:

  1. boolean flag = true
  2. Integer i = Integer.valueOf(0); 
  3. int j = 1; 
  4. int k = flag ? i.intValue() : j; 

這其實(shí)是三目運(yùn)算符的語(yǔ)法規(guī)范:當(dāng)?shù)诙?,第三位操作?shù)分別為基本類型和對(duì)象時(shí),其中的對(duì)象就會(huì)拆箱為基本類型進(jìn)行操作。

因?yàn)槔又?,flag ? i : j;片段中,第二段的i是一個(gè)包裝類型的對(duì)象,而第三段的j是一個(gè)基本類型,所以會(huì)對(duì)包裝類進(jìn)行自動(dòng)拆箱。如果這個(gè)時(shí)候i的值為null,那么久會(huì)發(fā)生NPE。(自動(dòng)拆箱導(dǎo)致空指針異常)

場(chǎng)景五、函數(shù)參數(shù)與返回值

這個(gè)比較容易理解,直接上代碼了:

  1. //自動(dòng)拆箱 
  2. public int getNum1(Integer num) { 
  3.  return num; 
  4. //自動(dòng)裝箱 
  5. public Integer getNum2(int num) { 
  6.  return num; 

自動(dòng)拆裝箱與緩存

Java SE的自動(dòng)拆裝箱還提供了一個(gè)和緩存有關(guān)的功能,我們先來(lái)看以下代碼,猜測(cè)一下輸出結(jié)果:

  1. public static void main(String... strings) { 
  2.  
  3.     Integer integer1 = 3; 
  4.     Integer integer2 = 3; 
  5.  
  6.     if (integer1 == integer2) 
  7.         System.out.println("integer1 == integer2"); 
  8.     else 
  9.         System.out.println("integer1 != integer2"); 
  10.  
  11.     Integer integer3 = 300; 
  12.     Integer integer4 = 300; 
  13.  
  14.     if (integer3 == integer4) 
  15.         System.out.println("integer3 == integer4"); 
  16.     else 
  17.         System.out.println("integer3 != integer4"); 
  18.  

我們普遍認(rèn)為上面的兩個(gè)判斷的結(jié)果都是false。雖然比較的值是相等的,但是由于比較的是對(duì)象,而對(duì)象的引用不一樣,所以會(huì)認(rèn)為兩個(gè)if判斷都是false的。

在Java中,==比較的是對(duì)象應(yīng)用,而equals比較的是值。

所以,在這個(gè)例子中,不同的對(duì)象有不同的引用,所以在進(jìn)行比較的時(shí)候都將返回false。奇怪的是,這里兩個(gè)類似的if條件判斷返回不同的布爾值。

上面這段代碼真正的輸出結(jié)果:

  1. integer1 == integer2 
  2. integer3 != integer4 

原因就和Integer中的緩存機(jī)制有關(guān)。在Java 5中,在Integer的操作上引入了一個(gè)新功能來(lái)節(jié)省內(nèi)存和提高性能。整型對(duì)象通過(guò)使用相同的對(duì)象引用實(shí)現(xiàn)了緩存和重用。

適用于整數(shù)值區(qū)間-128 至 +127。

只適用于自動(dòng)裝箱。使用構(gòu)造函數(shù)創(chuàng)建對(duì)象不適用。

具體的代碼實(shí)現(xiàn)可以閱讀Java中整型的緩存機(jī)制一文,這里不再闡述。

我們只需要知道,當(dāng)需要進(jìn)行自動(dòng)裝箱時(shí),如果數(shù)字在-128至127之間時(shí),會(huì)直接使用緩存中的對(duì)象,而不是重新創(chuàng)建一個(gè)對(duì)象。

其中的javadoc詳細(xì)的說(shuō)明了緩存支持-128到127之間的自動(dòng)裝箱過(guò)程。***值127可以通過(guò)-XX:AutoBoxCacheMax=size修改。

實(shí)際上這個(gè)功能在Java 5中引入的時(shí)候,范圍是固定的-128 至 +127。后來(lái)在Java 6中,可以通過(guò)java.lang.Integer.IntegerCache.high設(shè)置***值。

這使我們可以根據(jù)應(yīng)用程序的實(shí)際情況靈活地調(diào)整來(lái)提高性能。到底是什么原因選擇這個(gè)-128到127范圍呢?因?yàn)檫@個(gè)范圍的數(shù)字是最被廣泛使用的。 在程序中,***次使用Integer的時(shí)候也需要一定的額外時(shí)間來(lái)初始化這個(gè)緩存。

在Boxing Conversion部分的Java語(yǔ)言規(guī)范(JLS)規(guī)定如下:

如果一個(gè)變量p的值是:

  1. -128至127之間的整數(shù)(§3.10.1) 
  2.  
  3. true 和 false的布爾值 (§3.10.3) 
  4.  
  5. ‘\u0000’至 ‘\u007f’之間的字符(§3.10.4) 

范圍內(nèi)的時(shí),將p包裝成a和b兩個(gè)對(duì)象時(shí),可以直接使用a==b判斷a和b的值是否相等。

自動(dòng)拆裝箱帶來(lái)的問(wèn)題

當(dāng)然,自動(dòng)拆裝箱是一個(gè)很好的功能,大大節(jié)省了開(kāi)發(fā)人員的精力,不再需要關(guān)心到底什么時(shí)候需要拆裝箱。但是,他也會(huì)引入一些問(wèn)題。

包裝對(duì)象的數(shù)值比較,不能簡(jiǎn)單的使用==,雖然-128到127之間的數(shù)字可以,但是這個(gè)范圍之外還是需要使用equals比較。

前面提到,有些場(chǎng)景會(huì)進(jìn)行自動(dòng)拆裝箱,同時(shí)也說(shuō)過(guò),由于自動(dòng)拆箱,如果包裝類對(duì)象為null,那么自動(dòng)拆箱時(shí)就有可能拋出NPE。

如果一個(gè)for循環(huán)中有大量拆裝箱操作,會(huì)浪費(fèi)很多資源。

【本文是51CTO專欄作者Hollis的原創(chuàng)文章,作者微信公眾號(hào)Hollis(ID:hollischuang)】

戳這里,看該作者更多好文

責(zé)任編輯:武曉燕 來(lái)源: 51CTO專欄
相關(guān)推薦

2024-02-29 14:27:37

人工智能機(jī)器學(xué)習(xí)物聯(lián)網(wǎng)

2021-10-18 14:30:55

物聯(lián)網(wǎng)IOT

2023-05-11 15:24:12

2023-03-08 11:54:00

NB-IoT智能管理

2022-08-23 14:56:04

合成數(shù)據(jù)數(shù)據(jù)

2023-04-11 14:48:34

2022-02-15 08:07:17

測(cè)試軟件開(kāi)發(fā)

2023-02-23 15:32:55

2022-10-08 06:38:01

元宇宙NFT加密貨幣

2023-12-22 19:59:15

2021-08-04 16:06:45

DataOps智領(lǐng)云

2023-06-26 16:51:49

數(shù)字孿生數(shù)字技術(shù)

2017-03-07 15:13:28

Scala偏函數(shù)函數(shù)

2022-04-20 11:10:17

bias推薦系統(tǒng)debias

2021-08-06 09:21:26

Linux內(nèi)核 Coredump

2025-05-06 08:35:00

2021-09-04 19:04:14

配置LogbackJava

2018-09-28 14:06:25

前端緩存后端

2022-11-06 21:14:02

數(shù)據(jù)驅(qū)動(dòng)架構(gòu)數(shù)據(jù)

2025-04-03 10:56:47

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)