你知道Java中基本類型和包裝類的區(qū)別嗎

前情提要

?上一篇中籍滴,通過一道常見的面試題(即:String执庐、StringBuilder、StringBuffer的區(qū)別)酒繁,引申到Java中基本類型和包裝類的相關(guān)內(nèi)容四瘫。在這一篇中,我們將解決上一篇中引申出來的問題——基本類型和包裝類型到底有什么區(qū)別欲逃?
?首先,要弄明白這兩者的區(qū)別饼暑,我們就必須要知道基本數(shù)據(jù)類型和包裝類到底是啥稳析?各自都有些什么特性?
?請注意弓叛,除非特別注明彰居,否則本文篇中所涉及得到內(nèi)容都是基于jdk1.8來說的。
?先來了解一下基本數(shù)據(jù)類型吧撰筷。

關(guān)于基本數(shù)據(jù)類型

基本數(shù)據(jù)類型到底是個啥陈惰?

?關(guān)于基本數(shù)據(jù)類型的定義,我翻了一些資料毕籽,至今沒有在任何地方找到一個準(zhǔn)確的描述抬闯。
?這里我就談一下我個人的見解吧井辆,如果有朋友覺得下面的內(nèi)容有不妥的地方歡迎在評論區(qū)留下您的高見,大家共同進步溶握!

在一個變量定義后杯缺,該變量指向的只能是具體的數(shù)值而非內(nèi)存地址。這樣的變量就屬于基本數(shù)據(jù)類型睡榆。

?這一塊的內(nèi)容后續(xù)會再來補充萍肆,由于不是主線,暫時擱置影響也不大胀屿。

Java中基本數(shù)據(jù)類型有哪些

?在Java中塘揣,基本數(shù)據(jù)類型有8種,分別為:

布爾類型:boolean
字符類型:char
整數(shù)類型:byte宿崭、short亲铡、int、long
浮點類型:float劳曹、double

?各類型的詳細信息如下表:

類型描述 名稱 位數(shù) 字節(jié)數(shù) 默認值
布爾類型 boolean - - false
字符類型 char 16 2 'u0000'
整數(shù)類型 byte 8 1 0
整數(shù)類型 short 16 2 0
整數(shù)類型 int 32 4 0
整數(shù)類型 long 64 8 0L
浮點類型 float 32 4 0f
浮點類型 double 64 8 0d

?對于boolean而言奴愉,依賴于jvm廠商的具體實現(xiàn)。邏輯上理解是占用1位铁孵,但是實際中會考慮的因素較多锭硼。在此也不展開描述,如果有人問你究竟boolean占多少內(nèi)存空間蜕劝,你只需要回答:理論上1位(注意不是一個字節(jié))就可滿足需求檀头,實際還要看jvm的實現(xiàn)。

基本數(shù)據(jù)類型為什么不用new運算符岖沛?

?我們都知道new運算符可用于實例化一個對象暑始,也就是給對象實例分配一塊足夠大的內(nèi)存空間并返回指向該內(nèi)存的引用。注意婴削,這里所指的對象實際上是引用類型廊镜。引用對象開辟的內(nèi)存空間一般是在堆中。
?相對于引用類型來說唉俗,值類型一般存放在棧上(作為成員變量的時候才會放在堆中)嗤朴。因為虛擬機(根據(jù)虛擬機不同,boolean可能占用空間大小不同)對每一種基本類型的空間占用大小都是明確知曉的虫溜,所以不再需要new去開辟空間雹姊。
?實際中,Java的數(shù)據(jù)類型分為兩種:值類型和引用類型衡楞,我們習(xí)慣于把所有引用類型都統(tǒng)稱為對象吱雏。所以,基本數(shù)據(jù)類型不在我們理解的對象的定義范圍內(nèi)。

關(guān)于包裝類

包裝類的定義

?其實包裝類的意義從名字就能看出一些端倪歧杏。啥叫包裝镰惦,通俗了說就是把一個物體打包然后裝起來。舉個例子來說得滤,比如今天我在網(wǎng)上買了一顆蘋果陨献,等我收到貨的時候還是只有那一顆蘋果嗎?并不是懂更,我拿到的是一個貼了有運單號的箱子眨业,里面用了塑膠袋把蘋果給包起來了。同理沮协,包裝類也是一樣龄捡,每一個包裝類里面都包了一種基本數(shù)據(jù)類型。作用也和這個例子類似慷暂,是為了讓運輸更方便聘殖,讓蘋果更安全,讓我們操作更簡單行瑞。

包裝類的種類

?八種基本類型都有自己對應(yīng)的包裝類奸腺,分別為:

布爾類型:Boolean
字符類型:Character
整數(shù)類型:Byte、Short血久、Integer突照、Long
浮點類型:Float、Double

裝箱和拆箱氧吐、包裝類型的緩存機制

?下面我們以Integer為例讹蘑,了解一下什么是裝箱和拆箱,還有所謂的包裝類的緩存機制到底是什么筑舅?首先座慰,關(guān)于裝箱和拆箱的概念如下:

  1. 裝箱——將基本類型用各自對應(yīng)的包裝(引用)類型包裝起來:即基本類型->包裝類型;
  2. 拆箱——將包裝類型轉(zhuǎn)換為基本數(shù)據(jù)類型:即包裝類型->基本類型翠拣;

?例如下面的代碼將會發(fā)生裝箱和拆箱的過程版仔。

    public static void main(String[] args){
        // 裝箱
        Integer packageObject = 100;
        // 拆箱
        int baseObject = packageObject;
    }

?編譯上面的代碼(javac命令),查看對應(yīng)的.class文件的內(nèi)容(javap命令)误墓。

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=1
         0: bipush        100
         2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         5: astore_1
         6: aload_1
         7: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
        10: istore_2
        11: return
      LineNumberTable:
        line 9: 0
        line 11: 6
        line 12: 11

?可以看到裝箱的時候用的是Integer的valueOf方法邦尊;而拆箱的時候用的是intValue方法。在Integer中找到這兩個方法优烧。

    valueOf方法的API說明如下:
    /**
     * 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
     */

?因為篇幅原因,就不一步一步的點進去看了链峭,有興趣的朋友自行去翻源碼吧畦娄。上面的內(nèi)容已經(jīng)足夠說明問題了,上面的描述大概說了這些東西:

  1. 該返回的是一個基于int(這個是入?yún)ⅲ褪谴a中定義的100)值的Integer的實例對象熙卡;
  2. 首先會判斷入?yún)⒌姆秶诓辉赱-128,127]之間杖刷。
  3. 如果不在這之間,則會調(diào)用構(gòu)造方法返回一個新的Integer實例驳癌;
  4. 如果在這個范圍內(nèi)滑燃,則會從緩存中取一個Integer對象返回;

?Integer所謂的緩存其實是在Integer類的內(nèi)部定義了一個IntegerCache的class颓鲜,IntegerCache里面持有一個靜態(tài)并且final修飾的緩存數(shù)組表窘,在一開始這個數(shù)組里面就已經(jīng)存入了[-128,127]之間的整型值,當(dāng)你用自動裝箱的方式初始化一個Integer對象并且你的整型值在這個范圍內(nèi)的話甜滨,會自動從這個數(shù)組中找到對應(yīng)的Integer對象返回給你乐严,而不是重新創(chuàng)建一個Integer對象。

?下面再來看一下拆箱中遇到的intValue方法衣摩。

    intValue方法的API說明如下:
    /**
    * Returns the value of this {@code Integer} as an
    * {@code int}.
    */

?intValue方法的描述很簡單昂验,直接返回一個int類型的值。這個int值其實就是在Integer內(nèi)部包裝的基本數(shù)據(jù)類型(int)艾扮。

?到此既琴,(Integer類的)裝箱、拆箱以及緩存機制差不多咱們就已經(jīng)揭開那層面紗了泡嘴。事實上甫恩,八大包裝類型中除了浮點類型的包裝類(Double和Float)并沒有實現(xiàn)緩存技術(shù)外,其他的包裝類都實現(xiàn)了磕诊。

  1. Byte,Short,Integer,Long這四個包裝類都提供了數(shù)值[-128填物,127]之間的相應(yīng)類型的緩存;
  2. Character提供了數(shù)值在[0,127]之間的緩存;
  3. Boolean提供了取值在{True,False}之間的緩存霎终;
  4. 為什么浮點型不提供滞磺?因為浮點型的取值范圍太廣,不可能實現(xiàn)緩存莱褒。

基本數(shù)據(jù)類型和包裝數(shù)據(jù)類型常見的面試題

(一)為什么List<int> = new List<int>();類似這樣的代碼會報錯击困?

答:因為基本數(shù)據(jù)類型不支持泛型。
?List支持泛型广凸,但是泛型必須是對象阅茶。也就是說List支持所有繼承自O(shè)bject類的類型參數(shù),但基本數(shù)據(jù)類型并沒有繼承自O(shè)bject谅海,所以基本數(shù)據(jù)類型并不是對象脸哀。

(二)包裝類緩存的常見題
    // 題目
    Integer i1 = 55;
    Integer i2 = 55;
    Integer i3 = new Integer(55);
    Integer i4 = new Integer(55);
    Integer i5 = new Integer(56);
    Integer i6 = 1;
    System.out.println("i1 = i2 ? " + (i1 == i2));
    System.out.println("i3 = i4 ? " + (i3 == i4));
    System.out.println("i5 = i4 + i6 ? " + (i5 == i4 + i6));
    System.out.println("56 = i4 + i6 ? " + (56 == i4 + i6));
    Double d1 = 1.0d;
    Double d2 = 1.0d;
    System.out.println("d1 = d2 ? " + (d1 == d2));
    // 答案
    i1 = i2 ? true
    i3 = i4 ? false
    i5 = i4 + i6 ? true
    56 = i4 + i6 ? true
    d1 = d2 ? false
    // 解析
    // 從緩存數(shù)組中取一個值為55的Integer實例
    Integer i1 = 55;
    // 從緩存數(shù)組中取一個值為55的Integer實例
    Integer i2 = 55;
    // 創(chuàng)建一個值為55的Integer實例
    Integer i3 = new Integer(55);
    // 創(chuàng)建一個值為55的Integer實例
    Integer i4 = new Integer(55);
    // 創(chuàng)建一個值為56的Integer實例
    Integer i5 = new Integer(56);
    // 從緩存數(shù)組中取一個值為1的Integer實例
    Integer i6 = 1;
    // 只要值相等,從緩存數(shù)組中取出來的一定是同一個實例
    System.out.println("i1 = i2 ? " + (i1 == i2));
    // 雖然值相同扭吁,但是屬于兩個不同的實例(因為遇到了兩個new)
    System.out.println("i3 = i4 ? " + (i3 == i4));
    // Integer類不提供+的實現(xiàn)撞蜂,所以i4和i6先拆箱為基本數(shù)據(jù)類型盲镶,因為i5要和基本類型比較,i5也只能拆箱
    System.out.println("i5 = i4 + i6 ? " + (i5 == i4 + i6));
    // 同上一個
    System.out.println("56 = i4 + i6 ? " + (56 == i4 + i6));
    Double d1 = 1.0d;
    Double d2 = 1.0d;
    // Double不提供緩存機制蝌诡,每次都是new的新對象
    System.out.println("d1 = d2 ? " + (d1 == d2));
(三)Integer類的緩存區(qū)間為什么是[-128,127],為什么不把范圍定義的再廣一些溉贿?

?事實上,針對于Integer類浦旱,我們可以通過改參數(shù)的方式來設(shè)置這個區(qū)間的上下限宇色。那是不是意味著我的區(qū)間越大越好呢?
?并不是颁湖,看源碼的時候就會知道宣蠕,Integer類的緩存區(qū)間的每一個整型值都會被提前創(chuàng)建并加載到內(nèi)存中去。換句話說爷狈,這個區(qū)間越大植影,你的內(nèi)存就占用的越多。這是一個典型的時間和空間的抉擇問題涎永。緩存的意義就是拿空間換時間思币,但是你拿了太多的空間,可能換來的回報遠遠不是那點時間能補償?shù)昧说摹?/p>

(四)在Java中存在i+1<i的情況嗎羡微?

?存在谷饿,所有的基本類型都有位數(shù)的限制,比如int是32位妈倔,那么int能表示的整型范圍為[-2147483648,2147483647]博投,即:[負2的31次冪,正2的31次冪-1]。當(dāng)超過這個范圍時盯蝴,將發(fā)生溢出毅哗,溢出后該值將變?yōu)樨摂?shù)。

    int x = 2147483647;
    int y = x + 1;
    System.out.println(y);// 輸出:-2147483648
    System.out.println("y < x ? " + (y < x));// 輸出:y < x ? true

?關(guān)于為什么溢出后會變?yōu)樨摂?shù)捧挺,大家可自己演練一下虑绵。簡單提一下,32位的有符號數(shù)闽烙,第一位是符號位(為0表示正數(shù)翅睛,為1表示負數(shù))。所以32位能表示的最大的正數(shù)是[0111 1111 1111 1111 1111 1111 1111 1111]黑竞,寫成16進制就是0x7FFFFFFF捕发。再加1,低位向高位進位很魂,相加的結(jié)果變成[1000 0000 0000 0000 0000 0000 0000 0000]扎酷,表示成16進制則為0x80000000。這個結(jié)果一看就是負數(shù)遏匆,因為最高位的符號位已經(jīng)變成1了霞玄。至于為什么是-2147483648骤铃,就需要去算一下這個二進制串的補碼了。


擴展區(qū)域

擴展區(qū)域主體

這是一個沒有實現(xiàn)的擴展坷剧。


上一篇:String常見的面試題之String、StringBuilder喊暖、StringBuffer的區(qū)別是什么
下一篇:聊一聊虛擬機類加載機制吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惫企,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子陵叽,更是在濱河造成了極大的恐慌狞尔,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巩掺,死亡現(xiàn)場離奇詭異偏序,居然都是意外死亡,警方通過查閱死者的電腦和手機胖替,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進店門研儒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人独令,你說我怎么就攤上這事端朵。” “怎么了燃箭?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵冲呢,是天一觀的道長。 經(jīng)常有香客問我招狸,道長敬拓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任裙戏,我火速辦了婚禮乘凸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挽懦。我一直安慰自己翰意,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布信柿。 她就那樣靜靜地躺著冀偶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪渔嚷。 梳的紋絲不亂的頭發(fā)上进鸠,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天,我揣著相機與錄音形病,去河邊找鬼客年。 笑死霞幅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的量瓜。 我是一名探鬼主播司恳,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绍傲!你這毒婦竟也來了扔傅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤烫饼,失蹤者是張志新(化名)和其女友劉穎猎塞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杠纵,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡荠耽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了比藻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铝量。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖韩容,靈堂內(nèi)的尸體忽然破棺而出款违,到底是詐尸還是另有隱情,我是刑警寧澤群凶,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布插爹,位于F島的核電站,受9級特大地震影響请梢,放射性物質(zhì)發(fā)生泄漏赠尾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一毅弧、第九天 我趴在偏房一處隱蔽的房頂上張望气嫁。 院中可真熱鬧,春花似錦够坐、人聲如沸寸宵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽梯影。三九已至,卻和暖如春庶香,著一層夾襖步出監(jiān)牢的瞬間甲棍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工赶掖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留感猛,地道東北人七扰。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像陪白,于是被迫代替她去往敵國和親颈走。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,573評論 2 359