摘要:java中一切都是對象,為什麼int不用創建對象實例化,而可以直接使用? 本文分享自華為雲社區《【Java】對基本類型-整型數據結構的認識》,作者: huahua.Dr 。 整型數據類型有兩個:基本類型和引用類型(包裝類) 整數型基本類型:byte,int,short,long 其引用類型:B ...
摘要:java中一切都是對象,為什麼int不用創建對象實例化,而可以直接使用?
本文分享自華為雲社區《【Java】對基本類型-整型數據結構的認識》,作者: huahua.Dr 。
整型數據類型有兩個:基本類型和引用類型(包裝類)
整數型基本類型:byte,int,short,long
其引用類型:Byte,Integer,Short,Long
他們之前主要的區別在於:
- 存儲占用的空間不同,分別是1,2,4,8個位元組(每個位元組占用8bit),
- java裡面整數型預設使用的int數據類型,即如果直接寫整數字面量時,它表示的就是int類型,
- 整數型數據類型之間可以相互轉換,以int為預設中間類型,定義了一個整數值4,可以直接賦值給int,
- 也可以直接賦值給short和byte(只要數值範圍不超過byte和short的存儲範圍,可以自動向下轉型為byte或者short;如果超過則需要強轉但超過的高位數會丟失),也可以直接賦值給long,不需要強轉,會自動向上轉型。
- long數據類型可以直接使用L或l聲明
- 他們之間可以直接轉,只要數值範圍大於等於它的數值範圍,都可以直接轉;如果小於它的數值範圍就需要強轉,但強轉會導致數值丟失,編譯並不會報錯。
其他的基本相同;因此我們以int類型來展開詳細說明。
java中一切都是對象,為什麼int不用創建對象實例化,而可以直接使用?
單純是為了編程方便,引入基本類型。
既然引入了基本對象,那也不能破壞java是一個操作對象的語言吧?
所以後面引入了包裝類(wrapper class),為每種基本類型都引入了其對應的包裝類型,int基本類型的包裝類型就是Integer對象。
基本類型引入了包裝類型就能將,int基本類型就能像操作對象一樣去操作了嗎?
是的,還Java1.55引入了一個機制:自動拆箱和自動裝箱,使得基本類型和其對應的包裝類型可以相互轉換,原始基本類型可以自動轉換成對應的包裝對象。
基本類型和包裝類型是何時進行相互轉化,如何相互轉換?
自動拆箱與裝箱機制,可以在java變數賦值或者方法調用傳值與返回值或者容器存儲數據時直接使用基本類型或者對應的包裝類型;在java 1.5版本之前,使用容器集合(Collection)存儲數據時,只能存儲引用類型,需要存儲基本類型,則需要先將其轉成其對應的包裝類型才可以。
自動裝箱就是java自動的將基本類型數值轉換成其對應的包裝類型,自動裝箱時編譯器會自動調用其包裝類的valueOf()方法將基本類型數值轉成對象。
自動拆箱就是java自動將包裝類型轉換成其對應的基本類型,自動拆箱時編譯器會自動調用其包裝類的xxxValue()方法:如intValue()\doubleValue()\longValue()等將對象轉成基本類型數值。
當基本數據數值與包裝類型進行運算時,會觸發自動拆箱。
例子:
//before autoboxing Integer iObject = Integer.valueOf(3); Int iPrimitive = iObject.intValue() //after java5 Integer iObject = 3; //autobxing - primitive to wrapper conversion int iPrimitive = iObject; //unboxing - object to primitive conversion public static Integer show(Integer iParam){ System.out.println("autoboxing example - method invocation i: " + iParam); return iParam; } //autoboxing and unboxing in method invocation show(3); //autoboxing int result = show(3); //unboxing because return type of method is Integer
那自動拆箱和裝箱那麼方便,它有什麼缺點嗎?
由於編譯器的介入,增加了操作步驟和工作量,如果頻繁自動拆箱和裝箱,會影響程式性能:
Integer sum = 0; for(int i=1000; i<5000; i++){ sum+=i; }
上面的代碼sum+=i可以看成sum = sum + i,但是+這個操作符不適用於Integer對象,首先sum進行自動拆箱操作,進行數值相加操作,最後發生自動裝箱操作轉換成Integer對象。其內部變化如下:
int result = sum.intValue() + i; Integer sum = new Integer(result);
由於我們這裡聲明的sum為Integer類型,在上面的迴圈中會創建將近4000個無用的中間 Integer對象,在這樣龐大的迴圈中,會降低程式的性能並且加重了GC垃圾回收的工作量。因此在我們編程時,需要註意到這一點,正確地聲明變數類型,避免因為自動裝箱引起的性能問題。
還有一個問題:如果int與Integer混用,Integer自動拆箱成int時,會調用Integer.intValue()方法進行拆箱,如果Integer賦值為null,M那麼此時就會出現空指針異常。
如果一個類中有兩個重載方法,一個重載方法的參數是int基本類型,一個是Integer引用類型,那麼調用該方法時,會自動拆箱或裝箱嗎,實際會調用到那個方法?
Java1.5之前肯定是會根據實際參數是基本類型還是引用類型來選擇對應的方法;但是java1.5之後,有了自動拆箱和裝箱機制之後,也是不會觸發該機制的。也是根據實際參數類型來選擇對應的方法調用。下麵我們用實際代碼來說明一下:
public class Test { public static void main(String[] args) throws FileNotFoundException { Test test = new Test(); int para1 = 12; Integer para2 = 12; test.test(12); test.test(para2); } public void test(int para1) { System.out.println("我的參數是int基本類型,值:"+para1); } public void test(Integer para2) { System.out.println("我的參數是Integer類型,值:"+para2); } }
輸出:
我的參數是int基本類型,值:12
我的參數是Integer類型,值:12
那麼基本類型int與包裝類型Integer,數值進行比較是否相等會出現什麼情況?
情況有三種:==比較的是地址,對象Object的equals方法比較的也是地址,只不過包裝類型重寫了Object方法,比較的數值。
- int與int比較是否相等,使用==進行兩個數值相等的int比較,結果是true
- Integer與Integer比較是否相等,-128到127的Integer兩個數值相等的對象使用==比較結果是true,應為JVM為了省記憶體會將該範圍的數值緩存起來,共用一個Integer對象;該範圍以外的==比較結果是false;如果都是重新new 的兩個數值相等的Integer對象,==也是false,需要使用Integer對象的equals方法,比較才是true,
- int與Integer比較是否相等,Integer會自動拆箱,返回的結果是true.
// Example 1: == comparison pure primitive – no autoboxing int i1 = 1; int i2 = 1; System.out.println("i1==i2 : " + (i1 == i2)); // true // Example 2: equality operator mixing object and primitive Integer num1 = 1; // autoboxing int num2 = 1; System.out.println("num1 == num2 : " + (num1 == num2)); // true // Example 3: special case - arises due to autoboxing in Java Integer obj1 = 1; // autoboxing will call Integer.valueOf() Integer obj2 = 1; // same call to Integer.valueOf() will return same // cached Object System.out.println("obj1 == obj2 : " + (obj1 == obj2)); // true // Example 4: equality operator - pure object comparison Integer one = new Integer(1); // no autoboxing Integer anotherOne = new Integer(1); System.out.println("one == anotherOne : " + (one == anotherOne)); // false int num3 = 129; Integer obj3 = 129; System.out.println("num3==obj3:"+(num3==obj3));// true