??各位小伙伴們大家好,歡迎來到這個小扎扎的《Java核心技術 卷Ⅰ》筆記專欄,在這個系列專欄中我將記錄淺學這本書所得收獲,鑒于 看到就是學到、學到就是賺到 精神,這波簡直就是血賺
💡涉及的知識點速通
- 🛫 方法的參數傳遞機制是什么?
- 🪂 基本數據類型作參數
- 🪂 引用數據類型作參數
- 🛫 關于包裝類你都知道什么?
- 🪂 包裝類基本知識
- 🪂 什么是裝箱和拆箱?
- 🪂 包裝類cache緩存機制
🛫 方法的參數傳遞機制是什么?
??方法的參數分為基本數據類型和引用數據類型,基本數據類型就是前面說過的四類八種,具體都有什么可以參考下面這篇博客的🛫 強制and自動類型轉換都是啥?這個問題部分,在Java中除了這四類八種的基本數據類型之外都是引用數據類型
在答題之前先介紹一下相關概念
??參數傳遞機制的兩個專業術語:按值調用 表示方法接收到的是調用者提供的值;按引用調用 表示方法接收到的是調用者提供的變量地址
??方法參數的兩種形式:實參 就是方法調用的時候方法名后面的括號里的數據;形參 方法聲明的時候方法名后面的括號里的數據,這就相當于一種局部變量,只在它定義的這個方法內部有效
🪂 基本數據類型作參數
??基本數據類型的參數采用按值調用的傳遞機制,也就是說方法調用的時候傳過去的是一個值,但是實參并沒有作為這個值傳遞過去,而是將實參的副本傳遞過去,方法中對形參的所有操作都是對實參副本的操作,并不會更改實參的實際值
🪂 引用數據類型作參數
??引用數據類型的參數也是采用按值調用的傳遞機制,也就是說方法調用的時候傳過去的也是一個值,一個實參的副本??但是看上面代碼的運行結果,許多小伙伴是不是就懵了,不是說傳過去的是一個實參的副本嘛,為什么實參的結果值也互換了呢?別急,仔細想一想,數組是一個引用數據類型也就是說是一個對象,那么實參的arr是個什么?當然是這個數組對象的引用地址了,那么傳遞的副本也就是這個引用地址的副本,形參按照這個引用地址的副本對數組進行操作,當然也就按照地址操作了實參所對應的對象的值了。這么一來是不就是可以解釋的通了
??綜上所述,Java中方法的參數傳遞機制只有按值調用,并沒有按引用調用
🛫 關于包裝類你都知道什么?
🪂 包裝類基本知識
數據類型 | 包裝類 | 儲存空間(byte) | 大小 |
---|---|---|---|
byte | Byte | 1字節 | 8位 |
short | Short | 2字節 | 16位 |
int | Integer | 4字節 | 32位 |
long | Long | 8字節 | 64位 |
float | Float | 4字節 | 32位 |
double | Double | 8字節 | 64位 |
char | Character | 2字節 | 16位 |
boolean | Boolean | 1字節 | 8位 |
🚩每一個基本數據類型都有一個對應的包裝類,前六個類派生于公共的超類Number
🚩包裝類是不可變的,也即是說一旦構造了包裝器,就不允許更改它的值,與此同時包裝類還是final修飾的,因此不能派生他們的子類
🚩泛型也必須聲明成包裝類型,而不能使用基本數據類型
🚩包裝類的值比較需要使用equals方法,而不是==判斷
🪂 什么是裝箱和拆箱?
??Java主張一切皆對象的思想,但是基本數據類型并不是對象,于是就有了包裝類的概念。其中裝箱就是將一個基本數據類型包裝成其對應的包裝類,拆箱就是反過來將包裝類拆成對應的基本數據類型數據。根據轉換時是否使用方法,裝箱又稱為自動拆裝箱和手動拆裝箱
??手動裝箱有兩種方式:使用包裝類構造器、包裝類的valueOf方法;手動拆箱有一種:包裝類的xxxValue方法。但是Java提供了自動拆裝箱,如果二者相互復賦值的話就會自動轉換而無需使用方法進行轉換,且使用泛型定義的集合添加基本數據類型的時候也會自動裝箱為對應的包裝類型
🚩裝箱和拆箱是編譯器的工作
🪂 包裝類cache緩存機制
??從Java5開始,包裝類新增了自動拆、裝箱的功能,除此之外還新增了cache緩存機制,該機制會將取值在一定范圍內的值創建成相應的對象緩存起來,這些緩存起來的對象在以后使用到的時候就可以直接用,這樣就可以避免在這個范圍內的值重復創建造成的內存損耗從而降低性能。為了更好的了解這個機制,讓我們看一下接下來的這段代碼寫下自己的答案,然后結合cache機制的解釋再推測一下答案,最終結果在后面給出??這里通過源碼(下面給出),以Integer為例來了解一下包裝類的cache緩存機制,Integer類中有一個IntegerCache類,這個類的主要作用即就是創建[-128,127]之間的所有對象并添加到cache數組中,等到調用valueOf方法的時候就使用if判斷是不是在范圍內,如果在的話就直接在cache數組中直接返回,反之就使用構造器創建一個對應的Integer對象返回
private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint 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_VALUEh = 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() {}
}public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}
??但是你可能就會有疑問了,如果我就使用一次包裝類的話,它也會緩存創建范圍內的所有對象,這樣的話怎么實現節省內存提升性能呢?當然,包裝類的cache緩存機制是針對大程序而言的概念,小程序并不能很好地體現。于是當確定同值對象使用的次數很少時,我們就可以使用構造器來創建包裝類對象,因為緩存類只能通過valueOf方法才會生效
??你可能又有疑問了,使用自動裝箱直接賦值的形式創建包裝類對象會不會使用到緩存呢?答案是 會,因為自動裝箱底層就是調包裝類對應的valueOf方法,那么你是怎么確定的呢?對自動裝箱和自動拆箱代碼編譯生成的字節碼文件進行反編譯得出下面的內容,根據12和19行得知:自動裝箱調用的是valueOf方法,自動拆箱調用的是intValue方法
public class com.example.demo.code.AutoPacking {java.lang.Integer i1;int i2;public com.example.demo.code.AutoPacking();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: iconst_16: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: putfield #3 // Field i1:Ljava/lang/Integer;12: aload_013: new #4 // class java/lang/Integer16: dup17: iconst_218: invokespecial #5 // Method java/lang/Integer."<init>":(I)V21: invokevirtual #6 // Method java/lang/Integer.intValue:()I24: putfield #7 // Field i2:I27: return
}
通過上面的分析,我們就可以很容易的得出上面那段代碼的答案了
包裝類的緩存范圍
數據類型 | 包裝類 | 緩存范圍 |
---|---|---|
整型 | Byte、Short、Long、Integer | [-128,127] |
浮點型 | Float、Double | 無 |
字符型 | Character | [0,127] |
布爾型 | Boolean | true、false |