深入理解Java包裝類:自動裝箱拆箱與緩存池機制

深入理解Java包裝類:自動裝箱拆箱與緩存池機制

對象包裝器

Java中的數據類型可以分為兩類:基本類型引用類型。作為一門面向對象編程語言, 一切皆對象是Java語言的設計理念之一。但基本類型不是對象,無法直接參與面向對象操作,為了解決這個問題,Java讓每個基本類型都有一個與之對應的包裝器類型。

Java中有8種不可變的基本類型,分別為:

  • 整型byteshortintlong
  • 浮點類型floatdouble
  • 字符類型char
  • 布爾類型boolean
類型大小默認值示例
byte1字節0byte b = 10
short2字節0short s = 200
int4字節0int i = 1000
long8字節0Llong l = 5000L
float4字節0.0ffloat f = 3.14f
double8字節0.0ddouble d = 2.718
char2字節‘\u0000’char c = 'A'
boolean未明確定義falseboolean flag = true

這八種基本類型都有對應的包裝類分別為:ByteShortIntegerLongFloatDoubleCharacterBoolean (前6個派生于公共的超類Number)。包裝器類是不可變的,即一旦構造了包裝器,就不允許更改包裝在其中的值。同時,包裝器類還是final,因此不能派生它們的子類。

Java不是“一切皆對象”嗎,為什么還要保留基本數據類型?

包裝類是引用類型,對象的引用存儲在棧中,對象本身存儲在堆中;而對于基本數據類型,變量對應的內存塊直接存儲數據本身(棧中)。因此,基本數據類型讀寫效率更高效。在64位JVM上,在開啟引用壓縮的情況下,一個Integer對象占用16個字節的內存空間,而一個int類型數據只占用4字節的內存空間,前者對空間的占用是后者的4倍。也就是說,不管是讀寫效率還是存儲效率,基本類型都更高效。盡管Java強調面向對象,但為了性能做了妥協。

自動裝箱與拆箱

裝箱拆箱是實現基本數據類型與包裝類之間相互轉換的特性。Java 5引入自動裝箱/拆箱功能,進一步簡化了包裝類的使用。

  • 裝箱:將基本數據類型轉化為對應的包裝類對象。
  • 拆箱:將包裝類對象轉化為對應的基本數據類型值。

示例

Integer a = 100; // 自動裝箱 -> Integer.valueOf(100)int b = a; // 自動拆箱 -> a.intValue()// 自動裝箱和拆箱也適用于算術表達式
Integer n = 3;
n++; // 編譯器將自動插入一條對象拆箱的指令,然后進行自增運算,最后再將結果裝箱

裝箱其實就是調用了包裝類的valueOf()方法,拆箱其實就是調用了 xxxValue()方法。

API java.lang.Integer

  • int intValue()

    將這個Integer對象的值作為一個int返回(覆蓋Number類中的intValue方法)。

  • static Integer valueOf(String s)

    返回一個新的Integer對象,用字符串s表示的整數初始化。指定字符串必須表示一個十進制整數。

關于自動裝箱還有幾點需要注意:

  • 高頻裝箱拆箱(如循環)會產生大量臨時對象,消耗內存和GC資源:

    // 錯誤示例:每次循環觸發裝箱
    Long sum = 0L;
    for (long i = 0; i < 1e6; i++) {sum += i; // sum = Long.valueOf(sum.longValue() + i)
    }// 正確優化:使用基本類型
    long sum = 0L;
    for (long i = 0; i < 1e6; i++) {sum += i;
    }
    
  • 由于包裝器類引用可以為null,所以自動裝箱有可能會拋出一個NullPointerException異常:

    Integer n = null;
    System.out.println(2 * n) // throws NullPointerException
    
  • 如果在一個表達式中混合使用IntegerDouble類型,Integer值就會拆箱,提升為double,再裝箱為Double

    Integer n = 1;
    Double x = 2.0;
    System.out.println(true ? n : x); // 1.0
    
  • 裝箱和拆箱是編譯器要做的工作,而不是虛擬機。編譯器在生成類的字節碼時會插入必要的方法調用。虛擬機只是執行這些字節碼。

緩存池機制

緩存池是 Java 為優化包裝類對象創建和內存消耗而設計的核心機制,通過預創建和復用常用數值的包裝類對象,減少重復對象創建的開銷。Java 基本數據類型的包裝類型的大部分都用到了緩存機制來提升性能。

Byte,Short,Integer,Long 這 4 種包裝類默認創建了數值 [-128,127] 的相應類型的緩存數據,Character 創建了數值在 [0,127] 范圍的緩存數據,Boolean 直接返回 TRUE or FALSE

示例

Integer a = 100; // Integer.valueOf(100)
Integer b = 100; // Integer.valueOf(100) 
Integer c = 200; // Integer.valueOf(200)
Integer d = 200; // Integer.valueOf(200)System.out.println(a == b); // true
System.out.println(c == d); // false
System.out.println(c.equals(d)); //true 

Integer.valueOf()的緩存邏輯

public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i); // 超出緩存范圍時創建新對象
}

緩存池機制Java對-128 ~ 127范圍內的Integer對象預先生成并緩存ab指向同一個緩存對象,a == b比較對象地址,返回true200超出默認緩存范圍(-128 ~ 127),Integer.valueOf(200)每次會創建新對象,cd指向不同對象,c == d比較對象地址,返回false

對于 Integer,可以通過 JVM 參數 -XX:AutoBoxCacheMax=<size> 修改緩存上限,但不能修改下限 -128。實際使用時,并不建議設置過大的值,避免浪費內存,甚至是 OOM(全稱Out Of Memory, 即內存溢出)

  • 內存溢出:申請的內存超出了JVM能提供的內存大小,此時稱之為溢出。
  • 內存泄漏:申請使用完的內存沒有釋放,導致虛擬機不能再次使用該內存,此時這段內存就泄露了,因為申請者不用了,而又不能被虛擬機分配給別人用。

對于Byte,Short,Long ,Character 沒有類似 -XX:AutoBoxCacheMax 參數可以修改,因此緩存范圍是固定的,無法通過 JVM 參數調整。Boolean 則直接返回預定義的 TRUEFALSE 實例,沒有緩存范圍的概念。

Character的緩存邏輯

public static Character valueOf(char c) {if (c <= 127) { // must cachereturn CharacterCache.cache[(int)c];}return new Character(c);
}

Boolean的緩存邏輯

public static Boolean valueOf(boolean b) {return (b ? TRUE : FALSE);
}

兩種浮點數類型的包裝類 Float,Double 并沒有實現緩存機制

Float a = 3f;
Float b = 3f;
System.out.println(a == b);// 輸出 falseDouble c = 1.2;
Double d = 1.2;
System.out.println(c == d);// 輸出 false

下面這段代碼的輸出結果是什么?

Integer a = 40;
Integer b = new Integer(40);
System.out.println(a == b);

Integer a = 40自動裝箱等價于Integer a = Integer.valueOf(40)40在默認緩存范圍內,所以a直接使用的是緩存中的對象,而Integer b = new Integer(40)會直接創建新的對象。因此,答案是false

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78120.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78120.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78120.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

uniapp自定義拖拽排列

uniapp自定義拖拽排列并改變下標 <!-- 頁面模板 --> <template><view class"container"><view v-for"(item, index) in list" :key"item.id" class"drag-item" :style"{transform: translate(${activeInde…

基于SpringBoot的課程管理系統

前言 今天給大家分享一個基于SpringBoot的課程管理系統。 1 系統介紹 課程管理系統是一種專門為學校設計的軟件系統&#xff0c;旨在幫助學校高效地管理和組織各類課程信息。 該系統通常包括學生、教師和管理員三大角色。 他們可以通過系統進行選課、查看課程表、考試、進…

max31865典型電路

PT100讀取有很多種方案&#xff0c;常用的惠斯通電橋&#xff0c;和專用IC max31865 。 電阻溫度檢測器(RTD)是一種阻值隨溫度變化的電阻。鉑是最常見、精度最高的測溫金屬絲材料。鉑RTD稱為PT-RTD&#xff0c;鎳、銅和其它金屬亦可用來制造RTD。RTD具有較寬的測溫范圍&#x…

飛算 JavaAI 與 Spring Boot:如何實現微服務開發效率翻倍?

微服務架構憑借其高內聚、低耦合的特性&#xff0c;成為企業構建復雜應用系統的首選方案。然而&#xff0c;傳統微服務開發流程中&#xff0c;從服務拆分、接口設計到代碼編寫、調試部署&#xff0c;往往需要耗費大量時間與人力成本。Spring Boot 作為 Java 領域最受歡迎的微服…

(2)Docker 常用命令

文章目錄 Docker 服務器Docker 鏡像Docker 容器本地 RegistryRUN vs CMD vs ENTRYPOINTRUNCMDENTRYPOINT 限制容器對內存、CPU 和 IO 資源的使用內存CPUBlock IO設置權重bps 和 iops cgroup 和 namespacecgroupnamespacMount namespaceUTS namespaceIPC namespacePID namespace…

Django 實現電影推薦系統:從搭建到功能完善(附源碼)

前言&#xff1a;本文將詳細介紹如何使用 Django 構建一個電影推薦系統&#xff0c;涵蓋項目的搭建、數據庫設計、視圖函數編寫、模板渲染以及用戶認證等多個方面。&#x1f517;軟件安裝、環境準備 ? 【作者主頁—&#x1f4da;閱讀更多優質文章、獲取更多優質源碼】 目錄 一…

C#進階學習(七)常見的泛型數據結構類(2)HashSet和SortedSet

目錄 using System.Collections.Generic; // 核心命名空間 一、 HashSet 核心特性 常用方法 屬性 二、SortedSet 核心特性 1、整型&#xff08;int、long 等&#xff09; 2、字符串型&#xff08;string&#xff09; 3、字符型&#xff08;char&#xff09; 4、自定義…

SQL之DML(查詢語句:select、where)

&#x1f3af; 本文專欄&#xff1a;MySQL深入淺出 &#x1f680; 作者主頁&#xff1a;小度愛學習 select查詢語句 在開發中&#xff0c;查詢語句是使用最多&#xff0c;也是CRUD中&#xff0c;復雜度最高的sql語句。 查詢的語法結構 select *|字段1 [, 字段2 ……] from 表…

vue | 不同 vue 版本對復雜泛型的支持情況 · vue3.2 VS vue3.5

省流總結&#xff1a;defineProps 的泛型能力&#xff0c;來直接推導第三方組件的 props 類型 引入第三方庫的類型&#xff0c;并直接在 <script setup> 中作為 props 使用。這種類型一般是復雜泛型&#xff08;包含聯合類型、可選屬性、交叉類型、條件類型等&#xff0…

Unity-無限滾動列表實現Timer時間管理實現

今天我們來做一個UI里經常做的東西&#xff1a;無限滾動列表。 首先我們得寫清楚實現的基本思路&#xff1a; 所謂的無限滾動當然不是真的無限滾動&#xff0c;我們只要把離開列表的框再丟到列表的后面就行&#xff0c;核心理念和對象池是類似的。 我們來一點一點實現&#x…

Docker的基本概念和一些運用場景

Docker 是一種開源的容器化平臺&#xff0c;可以幫助開發人員更加高效地打包、發布和運行應用程序。以下是 Docker 的基本概念和優勢&#xff1a; 基本概念&#xff1a; 容器&#xff1a;Docker 使用容器來打包應用程序及其依賴項&#xff0c;容器是一個獨立且可移植的運行環境…

Unity中基于第三方插件擴展的對于文件流處理的工具腳本

在Unity的項目中對應文件處理,在很多地方用到,常見的功能,就是保存文件,加載文件,判斷文件或者文件夾是否存在,刪除文件等。 在之前已經寫過通過C#的IO實現的這些功能,可查看《Unity C# 使用IO流對文件的常用操作》,但是不能保證所有平臺都可以使用 現在基于第三方跨…

Flink介紹——實時計算核心論文之MillWheel論文詳解

引入 通過前面的文章&#xff0c;我們從S4到Storm&#xff0c;再到Storm結合Kafka成為當時的實時處理最佳實踐&#xff1a; S4論文詳解S4論文總結Storm論文詳解Storm論文總結Kafka論文詳解Kafka論文總結 然而KafkaStorm的第一代流式數據處理組合&#xff0c;還面臨的三個核心…

python異步協程async調用過程圖解

1.背景&#xff1a; 項目中有用到協程&#xff0c;但是對于協程&#xff0c;線程&#xff0c;進程的區別還不是特別了解&#xff0c;所以用圖示的方式畫了出來&#xff0c;用于理清三者的概念。 2.概念理解&#xff1a; 2.1協程&#xff0c;線程&#xff0c;進程包含關系 一…

【React】獲取元素距離頁面頂部的距離

文章目錄 代碼實現 代碼實現 import { useEffect, useRef, useState } from react;const DynamicPositionTracker () > {const [distance, setDistance] useState(0);const divRef useRef(null);useEffect(() > {const targetDiv divRef.current;if (!targetDiv) re…

26.OpenCV形態學操作

OpenCV形態學操作 形態學操作&#xff08;Morphological Operations&#xff09;源自二值圖像處理&#xff0c;主要用于分析和處理圖像中的結構元素&#xff0c;對圖像進行去噪、提取邊緣、分割等預處理步驟。OpenCV庫中提供了豐富的形態學函數&#xff0c;常見的包括&#xf…

邏輯回歸:損失和正則化技術的深入研究

邏輯回歸&#xff1a;損失和正則化技術的深入研究 引言 邏輯回歸是一種廣泛應用于分類問題的統計模型&#xff0c;尤其在機器學習領域中占據著重要的地位。盡管其名稱中包含"回歸"&#xff0c;但邏輯回歸本質上是一種分類算法。它的核心思想是在線性回歸的基礎上添…

大模型面經 | 介紹一下CLIP和BLIP

大家好,我是皮先生!! 今天給大家分享一些關于大模型面試常見的面試題,希望對大家的面試有所幫助。 往期回顧: 大模型面經 | 春招、秋招算法面試常考八股文附答案(RAG專題一) 大模型面經 | 春招、秋招算法面試常考八股文附答案(RAG專題二) 大模型面經 | 春招、秋招算法…

【MCP】第二篇:IDE革命——用MCP構建下一代智能工具鏈

【MCP】第二篇&#xff1a;IDE革命——用MCP構建下一代智能工具鏈 一、引言二、IDE集成MCP2.1 VSCode2.1.1 安裝VSCode2.1.2 安裝Cline2.1.3 配置Cline2.1.4 環境準備2.1.5 安裝MCP服務器2.1.5.1 自動安裝2.1.5.2 手動安裝 2.2 Trae CN2.2.1 安裝Trae CN2.2.2 Cline使用2.2.3 內…

【新能源科學與技術】MATALB/Simulink小白教程(一)實驗文檔【新能源電力轉換與控制仿真】

DP讀書&#xff1a;新能源科學與工程——專業課「新能源發電系統」 2025a 版本 MATLAB下面進入正題 仿真一&#xff1a;Buck 電路一、仿真目的二、仿真內容&#xff08;一&#xff09;Buck電路基本構成及工作原理&#xff08;二&#xff09;Buck電路仿真模型及元件連接&#xf…