Java工具類之:包裝類

来源:https://www.cnblogs.com/yychuyu/archive/2020/07/07/13263216.html
-Advertisement-
Play Games

Java工具類——包裝類 我們都知道,JDK 其實給我們提供了很多很多 Java 開發者已經寫好的現成的類,他們其實都可以理解成工具類,比如我們常見的集合類,日期相關的類,數學相關的類等等,有了這些工具類,你會發現它能很大程度的幫你節省時間,能很方便的實現你的需求。當然,沒有這些包,你也能實現你的需 ...


Java工具類——包裝類

我們都知道,JDK 其實給我們提供了很多很多 Java 開發者已經寫好的現成的類,他們其實都可以理解成工具類,比如我們常見的集合類,日期相關的類,數學相關的類等等,有了這些工具類,你會發現它能很大程度的幫你節省時間,能很方便的實現你的需求。當然,沒有這些包,你也能實現你的需求,但是你需要時間,今天我們主要是來學習一下包裝類。

一、包裝類介紹

1、為什麼需要包裝類?

我們知道 Java 語言是一個面向對象的編程語言,但是 Java 中的基本數據類型卻不是面向對象的,但是我們在實際使用中經常需要將基本數據類型轉換成對象,便於操作,比如,集合的操作中,這時,我們就需要將基本類型數據轉化成對象,所以就出現了包裝類。

2、包裝類是什麼呢?

包裝類,顧名思義就是將什麼經過包裝的類,那麼是將什麼包裝起來的呢,顯然這裡是將基本類型包裝起來的類。包裝類的作用就是將基本類型轉成對象,將基本類型作為對象來處理。

Java 中我們知道,基本數據類型有8個,所以對應的包裝類也是8個,包裝類就是基本類型名稱首字母大寫。但Integer 和 Character 例外,它們顯示全稱,如下麵表格所示:

基本數據類型 對應包裝類
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

二、包裝類的繼承關係

通過閱讀 Java8 的 API 官方文檔或者看源代碼我們可以得知8個包裝類的繼承關係如下:

通過以上的繼承關係圖,我們其實可以這樣記憶,包裝類裡面有6個與數字相關的都是繼承自 Number 類,而其餘兩個不是與數字相關的都是預設繼承 Object 類。通過看 API 官方文檔,我們還可以得知這8個包裝類都實現了Serializable , Comparable 介面。比如下圖的 Integer 類

public final class Integer extends Number implements Comparable<Integer> {}

三、包裝類的使用方法(基本操作)

接下來關於包裝類的講解我就講Integer包裝類,其他的都依此類推,用法和操作都是差不多的,只是名字不一樣而已。

1、包裝類的構造方法

8個包裝類都有帶自己對應類型參數的構造方法,其中8個包裝類中除了Character還有構造方法重載,參數是String類型的。

Integer one = new Integer(666);
Integer two = new Integer("666");

2、包裝類的自動拆裝箱

在瞭解自動拆裝箱之前,我們得先知道什麼是拆箱和裝箱。其實拆裝箱主要應對基本類型與包裝類型的相互轉換問題。

  • 裝箱:將基本類型轉換成包裝類型的過程叫做裝箱。

  • 拆箱:將包裝類型轉換成基本類型的過程叫做拆箱。

其實,在 JDK1.5 版本之前,是沒有自動拆裝箱的,開發人員要手動進行裝拆箱:

//手動裝箱,也就是將基本類型10轉換為引用類型
Integer integer = new Integer(10);
//或者
Integer integer1 = Integer.valueOf(10);

//手動拆箱,也就是將引用類型轉換為基本類型
int num = integer.intValue();

而在在 JDK1.5 版本之後,為了減少開發人員的工作,提供了自動裝箱與自動拆箱的功能。實現了自動拆箱和自動裝箱,如下方代碼所示:

//自動裝箱
Integer one = 1;
//自動拆箱
int two = one + 10;

其實以上兩種方式本質上是一樣得,只不過一個是自動實現了,一個是手動實現了。至於自動拆裝箱具體怎麼實現的我這裡不做深入研究。

四、包裝類的緩存機制

我們首先來看看以下代碼,例1:

public static void main(String[] args) {
  Integer i1 = 100;
  Integer i2 = 100;
  Integer i3 = new Integer(100);
  Integer i4 = new Integer(100);
  System.out.println(i1 == i2);//true
  System.out.println(i1 == i3);//false
  System.out.println(i3 == i4);//false
  System.out.println(i1.equals(i2));//true
  System.out.println(i1.equals(i3));//true
  System.out.println(i3.equals(i4));//true
}

當我們修改了值為200的時候,例2:

public static void main(String[] args) {
  Integer i1 = 200;
  Integer i2 = 200;
  Integer i3 = new Integer(200);
  Integer i4 = new Integer(200);
  System.out.println(i1 == i2);//false
  System.out.println(i1 == i3);//false
  System.out.println(i3 == i4);//false
  System.out.println(i1.equals(i2));//true
  System.out.println(i1.equals(i3));//true
  System.out.println(i3.equals(i4));//true
}

通過上面兩端代碼,我們發現修改了值,第5行代碼的執行結果竟然發生了改變,為什麼呢?首先,我們需要明確第1行和第2行代碼實際上是實現了自動裝箱的過程,也就是自動實現了 Integer.valueOf 方法,其次,比較的是地址,而 equals 比較的是值(這裡的 eauals 重寫了,所以比較的是具體的值),所以顯然最後五行代碼的執行結果沒有什麼疑惑的。既然比較的是地址,例1的第5行代碼為什麼會是true呢,這就需要我們去瞭解包裝類的緩存機制。

其實看Integer類的源碼我們可以發現在第780行有一個私有的靜態內部類,如下:

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() {}
}

我們知道,靜態的內部類是在整個 Integer 載入的時候就已經載入完成了,以上代碼初始化了一個 Integer 類型的叫 cache 的數組,取值範圍是[-128, 127]。緩存機制的作用就是提前實例化相應範圍數值的包裝類對象,只要創建處於緩存範圍的對象,就使用已實例好的對象。從而避免重覆創建多個相同的包裝類對象,提高了使用效率。如果我們用的對象範圍在[-128, 127]之內,就直接去靜態區找對應的對象,如果用的對象的範圍超過了這個範圍,會幫我們創建一個新的 Integer 對象,其實下麵的源代碼就是這個意思:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

所以 例1 代碼里,i1 和i2 是100,值的範圍在[-128, 127],所以直接區靜態區找,所以i1和i2指向的地址是同一個,所以 i1==i2;而在例2的代碼里,i1 和i2 是200,值的範圍不在在[-128, 127],所以分別創建了一個新的對象,放在了堆記憶體里,各自指向了不同的地址,所以地址都不同了,自然 i1 不等於 i2。

通過分析源碼我們可以發現,只有 double 和 float 的自動裝箱代碼沒有使用緩存,每次都是 new 新的對象,其它的6種基本類型都使用了緩存策略。
使用緩存策略是因為,緩存的這些對象都是經常使用到的(如字元、-128至127之間的數字),防止每次自動裝箱都創建一次對象的實例。

五、包裝類和基本數據類型的區別

  • 預設值不同

包裝類的預設值是null,而基本數據類型是對應的預設值(比如整型預設值是0,浮點型預設值是0.0)

  • 存儲區域不同

基本數據類型是把值保存在棧記憶體里,包裝類是把對象放在堆中,然後通過對象的引用來調用他們

  • 傳遞方式不同

基本數據類型變數空間裡面存儲的是值,傳遞的也是值,一個改變,另外一個不變,而包裝類屬於引用數據類型,變數空間存儲的是地址(引用),傳遞的也是引用,一個變,另外一個跟著變。

五、小結

​ 以上就是我對於Java包裝類的個人理解,其實學習這些工具類還有一個更好的學習方式,就是去看官方文檔(API官方文檔地址:https://docs.oracle.com/javase/8/docs/api/)


公眾號:良許Linux

有收穫?希望老鐵們來個三連擊,給更多的人看到這篇文章


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 上一篇【.Net Core微服務入門全紀錄(六)——EventBus-事件匯流排】中使用CAP完成了一個簡單的Eventbus,實現了服務之間的解耦和非同步調用,並且做到數據的最終一致性。這一篇將使用IdentityServer4來搭建一個鑒權中心,來完成授權認證相關的功能。 IdentitySe ...
  • private:私有成員,在類的內部才可以訪問。 protected:保護成員,該類內部和繼承類中可以訪問。 public:公共成員,完全公開,沒有訪問限制。 internal:當前程式集內可以訪問。 ...
  • 一、TLS 線程本地存儲(Thread Local Storage),字面意思就是專屬某個線程的存儲空間。變數大體上分為全局變數和局部變數,一個進程中的所有線程共用地址空間,這個地址空間被劃分為幾個固有的區域,比如堆棧區,全局變數區等,全局變數存儲在全局變數區,虛擬地址固定;局部變數存儲在堆棧區,虛... ...
  • 微服務之間的通信之gRPC 介紹 gRPC是一種與語言無關的高性能遠程過程調用 (RPC) 框架,gRPC是Google發佈的基於HTTP 2.0傳輸層協議承載的高性能開源軟體框架,提供了支持多種編程語言的、對網路設備進行配置和納管的方法。由於是開源框架,通信的雙方可以進行二次開發,所以客戶端和服務 ...
  • 本文是本系列的完結篇。本系列前面的文章: 邏輯式編程語言極簡實現(使用C#) - 1. 邏輯式編程語言介紹 邏輯式編程語言極簡實現(使用C#) - 2. 一道邏輯題:誰是凶手 邏輯式編程語言極簡實現(使用C#) - 3. 運行原理 下午,吃飽飯的老明和小皮,各拿著一杯剛買的咖啡回到會議室,開始了邏輯 ...
  • 前言 隨著近些年微服務的流行,有越來越多的開發者和團隊所採納和使用,它的確提供了很多的優勢也解決了很多的問題,但是我們也知道也並不是銀彈,提供優勢的同時它也給我們的開發人員和團隊也帶來了很多的挑戰。 為了迎接或者採用這些新技術,開發團隊需要更加註重一些流程或工具的使用,這樣才能更好的適應這些新技術所 ...
  • 在園子裡面有很多關於各種技術細節的研究文章,都是比較牛逼的框架研究;但是一直沒有看到關於怎麼樣提高開發效率的文章,大多提高開發效率的文章都是關於自動化等方面的輔助工具類型的,而不是開發中的一些小技巧;今天從編碼規範、編碼技巧、開發思想、設計模式等各方面的經驗來分享如何提高開發效率。 ...
  • ip.txt 192.168.0.105 123455 192.168.0.106 123456 192.168.0.107 123457 192.168.0.108 123458 passwd.sh #!/bin/bash for ip in `awk '{print $1}' ip.txt` d ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...