自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java 中為什么設(shè)計(jì)了包裝類

開發(fā) 后端
在 Java 中,萬物皆對(duì)象,所有的操作都要求用對(duì)象的形式進(jìn)行描述。但是 Java 中除了對(duì)象(引用類型)還有八大基本類型,它們不是對(duì)象。

[[384127]]

本文轉(zhuǎn)載自微信公眾號(hào)「飛天小牛肉」,作者飛天小牛肉。轉(zhuǎn)載本文請(qǐng)聯(lián)系飛天小牛肉公眾號(hào)。

全文脈絡(luò)思維導(dǎo)圖如下:

 

1. 為什么需要包裝類

在 Java 中,萬物皆對(duì)象,所有的操作都要求用對(duì)象的形式進(jìn)行描述。但是 Java 中除了對(duì)象(引用類型)還有八大基本類型,它們不是對(duì)象。那么,為了把基本類型轉(zhuǎn)換成對(duì)象,最簡(jiǎn)單的做法就是「將基本類型作為一個(gè)類的屬性保存起來」,也就是把基本數(shù)據(jù)類型包裝一下,這也就是包裝類的由來。

這樣,我們先自己實(shí)現(xiàn)一個(gè)簡(jiǎn)單的包裝類,以包裝基本類型 int 為例:

  1. // 包裝類 MyInt 
  2. public class MyInt { 
  3.     private int number; // 基本數(shù)據(jù)類型 
  4.      
  5.     public Int (int number){ // 構(gòu)造函數(shù),傳入基本數(shù)據(jù)類型 
  6.         this.number = number; 
  7.     } 
  8.      
  9.     public int intValue(){ // 取得包裝類中的數(shù)據(jù) 
  10.         return this.number; 
  11.     } 

測(cè)試一下這個(gè)包裝類:

  1. public static void main(String[] args) { 
  2.     MyInt temp = new Int(100); // 100 是基本數(shù)據(jù)類型, 將基本數(shù)據(jù)類型包裝后成為對(duì)象 
  3.     int result = temp.intValue(); // 從對(duì)象中取得基本數(shù)據(jù)類型 
  4.     System.out.println(result); 

當(dāng)然,我們自己實(shí)現(xiàn)的這個(gè)包裝類非常簡(jiǎn)單,Java 給我們提供了更完善的內(nèi)置包裝類:

基本類型 對(duì)應(yīng)的包裝類(位于 java.lang 包中)
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

前 6 個(gè)類派生于公共的超類 Number,而 Character 和 Boolean 是 Object 的直接子類。

來看看包裝類的聲明,以 Integer 為例:

 

被 final 修飾,也就是說 Java 內(nèi)置的「包裝類是無法被繼承的」。

2. 裝箱與拆箱

OK,現(xiàn)在我們已經(jīng)知道了,存在基本數(shù)據(jù)類型與其對(duì)應(yīng)的包裝類,那么,他們之間互相的轉(zhuǎn)換操作就稱為裝箱與拆箱:

  • 裝箱:將基本數(shù)據(jù)類型轉(zhuǎn)換成包裝類(每個(gè)包裝類的構(gòu)造方法都可以接收各自數(shù)據(jù)類型的變量)
  • 拆箱:從包裝類之中取出被包裝的基本類型數(shù)據(jù)(使用包裝類的 xxxValue 方法)

下面以 Integer 為例,我們來看看 Java 內(nèi)置的包裝類是如何進(jìn)行拆裝箱的:

  1. Integer obj = new Integer(10);  // 自動(dòng)裝箱 
  2. int temp = obj.intValue();   // 自動(dòng)拆箱 

可以看出,和上面我們自己寫的包裝類使用方式基本一樣,事實(shí)上,Integer 中的這兩個(gè)方法其底層實(shí)現(xiàn)和我們上述寫的代碼也是差不多的。

 

不知道各位發(fā)現(xiàn)沒,value 被聲明為 final 了,也就是說「一旦構(gòu)造了包裝器,就不允許更改包裝在其中的值」。

另外,需要注意的是,這種形式的代碼是 「JDK 1.5 以前」的!!!「JDK 1.5 之后」,Java 設(shè)計(jì)者為了方便開發(fā)提供了「自動(dòng)裝箱」與「自動(dòng)拆箱」的機(jī)制,并且可以直接利用包裝類的對(duì)象進(jìn)行數(shù)學(xué)計(jì)算。

還是以 Integer 為例我們來看看自動(dòng)拆裝箱的過程:

  1. Integer obj = 10;   // 自動(dòng)裝箱. 基本數(shù)據(jù)類型 int -> 包裝類 Integer 
  2. int temp = obj;   // 自動(dòng)拆箱. Integer -> int 
  3. obj ++; // 直接利用包裝類的對(duì)象進(jìn)行數(shù)學(xué)計(jì)算 
  4. System.out.println(temp * obj);  

看見沒有,基本數(shù)據(jù)類型到包裝類的轉(zhuǎn)換,不需要像上面一樣使用構(gòu)造函數(shù),直接 = 就完事兒;同樣的,包裝類到基本數(shù)據(jù)類型的轉(zhuǎn)換,也不需要我們手動(dòng)調(diào)用包裝類的 xxxValue 方法了,直接 = 就能完成拆箱。這也是將它們稱之為自動(dòng)的原因。

 

我們來看看這段代碼反編譯后的文件,底層到底是什么原理:

  1. Integer obj = Integer.valueOf(10); 
  2. int temp = obj.intValue(); 

可以看見,自動(dòng)裝箱的底層原理是調(diào)用了包裝類的 valueOf 方法,而自動(dòng)拆箱的底層調(diào)用了包裝類的 intValue() 方法。

3. 不簡(jiǎn)單的 Integer.valueOf

我們上面已經(jīng)看過了用于自動(dòng)拆箱的 intValue 方法的源碼,非常簡(jiǎn)單。接下來咱來看看用于自動(dòng)裝箱的 valueOf,其他包裝類倒沒什么好說的,不過 Integer 中的這個(gè)方法還是有點(diǎn)東西的:

 

IntegerCache 又是啥,點(diǎn)進(jìn)去看看:

 

IntegerCache 是 Integer 類中的靜態(tài)內(nèi)部類,綜合這兩段代碼,我們大概也能知道,IntegerCache 其實(shí)就是個(gè)「緩存」,其中定義了一個(gè)緩沖區(qū) cache,用于存儲(chǔ) Integer 類型的數(shù)據(jù),「緩存區(qū)間是 [-128, 127]」。

回到 valueOf 的源碼:它首先會(huì)判斷 int 類型的實(shí)參 i 是否在可緩存區(qū)間內(nèi),如果在,就直接從緩存 IntegerCache 中獲取對(duì)應(yīng)的 Integer 對(duì)象;如果不在緩存區(qū)間內(nèi),則會(huì) new 一個(gè)新的 Integer 對(duì)象。

結(jié)合這個(gè)特性,我們來看一個(gè)題目,兩種類似的代碼邏輯,但是卻得到完全相反的結(jié)果。:

  1. public static void main(String args[]) { 
  2.     Integer a1 = 127; 
  3.     Integer a2 = 127; 
  4.     System.out.println(a1 == a2); // true 
  5.  
  6.     Integer b1 = 128; 
  7.     Integer b2 = 128; 
  8.     System.out.println(b1 == b2); // false 

我們知道,== 擁有兩種應(yīng)用場(chǎng)景:

  • 對(duì)于引用類型來說,判斷的是內(nèi)存地址是否相等
  • 對(duì)于基本類型來說,判斷的是值是否相等

從 a1 開始看,由于其值在 InterCache 的緩存區(qū)間內(nèi),所以這個(gè) Integer 對(duì)象會(huì)被存入緩存。而在創(chuàng)建 a2 的時(shí)候,由于其值和 a1 相等,所以直接從緩存中取出值為 127 的 Integer 對(duì)象給 a2 使用,也就是說,a1 和 a2 這兩個(gè) Integer 的對(duì)象引用都指向同一個(gè)地址。

 

對(duì)于 b1 和 b2 來說,由于 128 不在 IntegerCache 的緩存區(qū)間內(nèi),那就只能自己老老實(shí)實(shí)開辟空間了,所以 b1 和 b2 指向不同的內(nèi)存地址。

很顯然,由于 InterCache 緩存機(jī)制的存在,可能會(huì)讓我們?cè)诰幊痰臅r(shí)候出現(xiàn)困惑,因此最好使用 .equals 方法來比較 Integer 值是否相等。Integer 重寫了 .equals 方法:

 

當(dāng)然,其他包裝類雖然沒有緩存機(jī)制,但是也都重載了 .equals 方法,用于根據(jù)值來判斷是否相等。因此,得出結(jié)論,「使用 equals 方法來比較兩個(gè)包裝類對(duì)象的值」。

4. Object 類可以接收所有數(shù)據(jù)類型

綜上,有了自動(dòng)拆裝箱機(jī)制,基本數(shù)據(jù)類型可以自動(dòng)的被轉(zhuǎn)為包裝類,而 Object 是所有類的父類,也就是說,「Object 可以接收所有的數(shù)據(jù)類型了」(引用類型、基本類型)!!!

不信你可以試試,直接用 Object 類接收一個(gè)基本數(shù)據(jù)類型 int,完全是可以的。

  1. Object obj = 10; 
  2. int temp = (Integer) obj; 

解釋一下上面這段代碼發(fā)生了什么,下面這張圖很重要,大家仔細(xì)看:

 

5. 包裝類在集合中的廣泛使用

其實(shí)包裝類最常見的使用就是在集合中,因?yàn)榧喜辉试S存儲(chǔ)基本類型的數(shù)據(jù),只能存儲(chǔ)引用類型的數(shù)據(jù)。那如果我們想要存儲(chǔ) 1、2、3 這樣的基本類型數(shù)據(jù)怎么辦?舉個(gè)例子,我們可以如下聲明一個(gè) Integer對(duì)象的數(shù)組列表:

  1. ArrayList<Integer> list = new ArrayList<>(); 

往這個(gè)列表中添加 int 型數(shù)據(jù):

  1. list.add(3);  

上面這個(gè)調(diào)用在底層將會(huì)發(fā)生自動(dòng)裝箱操作:

  1. int n = list.get(i); 

基本數(shù)據(jù)類型 int 會(huì)被轉(zhuǎn)換成 Integer 對(duì)象存入集合中。

我們?cè)賮韽倪@個(gè)集合中根據(jù)某個(gè)下標(biāo) i 獲取對(duì)應(yīng)的 Integer 對(duì)象,并用基本數(shù)據(jù)類型 int 接收:

int n = list.get(i);

上面這個(gè)調(diào)用在底層將會(huì)發(fā)生自動(dòng)拆箱操作:

  1. int n = list.get(i).intValue(); 

6. 數(shù)據(jù)類型轉(zhuǎn)換

另外,除了在集合中的廣泛應(yīng)用,包裝類還包含一個(gè)重要功能,那就是提供將String型數(shù)據(jù)變?yōu)榛緮?shù)據(jù)類型的方法,使用幾個(gè)代表的類做說明:

Integer:

 

Double:

 

Boolean:

 

這些方法均被 static 標(biāo)識(shí),也就是說它們被各自對(duì)應(yīng)的所有對(duì)象共同維護(hù),直接通過類名訪問該方法。舉個(gè)例子:

String str = "10";int temp = Integer.parseInt(str);// String -> intSystem.out.println(temp * 2); // 20

需要特別注意的是:Character 類里面并不存在字符串變?yōu)樽址姆椒?,因?yàn)?String 類中已經(jīng)有一個(gè) charAt()的方法可以根據(jù)索引取出字符內(nèi)容。

 

責(zé)任編輯:武曉燕 來源: 飛天小牛肉
相關(guān)推薦

2020-06-27 09:01:53

Java包裝類編程語言

2024-12-26 07:41:47

Java類型ArrayList

2020-07-08 07:56:08

Java工具類包裝類

2017-02-27 15:19:04

2023-12-11 12:03:14

Python工具元組

2020-05-13 15:57:59

聚類分析算法監(jiān)督學(xué)習(xí)

2020-06-10 09:06:48

MongoDB架構(gòu)高可用

2024-06-24 07:58:00

2023-07-23 17:19:34

人工智能系統(tǒng)

2022-06-13 21:52:02

CDN網(wǎng)絡(luò)節(jié)點(diǎn)

2023-10-10 08:24:12

2021-10-11 09:32:40

包裝類型屬性

2021-09-14 08:50:38

Kubernetes容器Docker

2016-09-27 21:25:08

Go語言Ken Thompso

2022-06-07 08:39:35

RPCHTTP

2019-06-18 14:01:44

百度互聯(lián)網(wǎng)人工智能

2022-05-30 10:23:59

HTTPHTTP 1.1TCP

2015-07-09 14:05:11

Web Web設(shè)計(jì)

2019-03-11 08:36:11

Python代碼Flask

2020-09-16 06:51:37

Java線程JVM
點(diǎn)贊
收藏

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