Java中int和Integer相互轉換
Java是一種面嚮物件語言,為了能將基本型別視為物件來處理,並能連線相關的方法,Java為每個基本資料型別都提供了包裝類,這樣便可以把這些基本型別轉化為物件來處理。
基本資料型別 | 包裝類 | 基本資料型別 | 包裝類 |
boolean | Boolean | int | Integer |
byte | Byte | long | Long |
char | Character | float | Float |
short | Short | double | Double |
Java int與integer的區別
int與integer的區別從大的方面來說就是基本資料型別與其包裝類的區別:
int 是基本型別,直接存數值,而integer是物件,用一個引用指向這個物件
1.Java 中的資料型別分為基本資料型別和引用資料型別
int 是前者而integer 是後者(也就是一個類);因此在類進行初始化時int類的變數初始為0.而Integer的變數則初始化為null.
2.初始化時:
int i =1;Integer i= new Integer(1);(要把integer 當做一個類看);但由於有了自動裝箱和拆箱
使得對Integer類也可使用:Integer i= 1;
注意:Integer i=1編譯時被翻譯成Integer i=Integer.valueOf(i);
int 是基本資料型別(面向過程留下的痕跡,不過是對java的有益補充),Integer 是一個類,是int的擴充套件,定義了很多的轉換方法
類似的還有:float Float;double Double等,而且還提供了處理 int 型別時非常有用的其他一些常量和方法
舉個例子:當需要往ArrayList,HashMap中放東西時,像int,double這種內建型別是放不進去的,因為容器都是裝 object的,這是就需要這些基本型別的包裝類了。
Java中int和Integer關係是比較微妙的。關係如下:
1.int是基本的資料型別;
2.Integer是int的包裝類;
3.int和Integer都可以表示某一個數值;
4.int和Integer不能夠互用,因為他們兩種不同的資料型別;
舉例說明
ArrayList al=new ArrayList();
int n=40;
Integer nI=new Integer(n);
al.add(n);//不可以
al.add(nI);//可以
並且泛型定義時也不支援int: 如:List<Integer> list = new ArrayList<Integer>();可以 而List<int> list = new ArrayList<int>();則不行
Integer與int互轉
int轉Integer
int i=0;
Integer wrapperi=new Integer(i);
Integer轉int
Integer wrapperi=new Integer(0);
int i=wrapperi;
JDK1.5以後的int轉Integer
JDK1.5以後,Java為我們提供了更為豐富的轉換方法。
其中最值得一提的就是自動裝包/自動拆包(AutoBoxing/UnBoxing)。
此功能大大豐富了基本型別(primitive type)資料與它們的包裝類(Wrapper Class)
的使用。
由於AutoBoxing的存在,以下程式碼在JDK1.5的環境下可以編譯通過並執行。
int i = 0;
Integer wrapperi = i;
JDK1.5為Integer增加了一個全新的方法:
public static Integer valueOf(int i)
此方法與new Integer(i)的不同處在於:
valueOf(i)方法返回一個表示指定的int值的Integer例項,new Integer(i)產生一個新的Integer物件。
JDK API文件中對這個新的valueOf方法有明確的解釋:
如果不需要新的 Integer 例項,則通常應優先使用該方法,而不是構造方法 Integer(int),因為該方法有可能通過快取經常請求的值而顯著提高空間和時間效能。
但這個解釋有點晦澀難懂。為什麼該方法有可能通過快取經常請求的值而顯著提高效能?
通過反編譯工具檢視valueOf方法。
/*
* 返回一個表示指定的 int 值的 Integer 例項。如果不需要新的 Integer 例項,則
* 通常應優先使用該方法,而不是構造方法 Integer(int),因為該方法有可能通過
* 快取經常請求的值而顯著提高空間和時間效能。
* @param i an <code>int</code> value.
* @return a <tt>Integer</tt> instance representing <tt>i</tt>.
* @since 1.5
*/
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
可以看到對於範圍在-128到127的整數,valueOf方法做了特殊處理。
採用IntegerCache.cache[i + offset]這個方法。
從名字,我們可以猜出這是某種快取機制。
進一步跟蹤IntegerCache這個類,此類程式碼如下
/*
* IntegerCache內部類
* 其中cache[]陣列用於存放從-128到127一共256個整數
*/
private static class IntegerCache {
private IntegerCache(){}
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}
這就是valueOf方法真正的優化方法,當-128=<i<=127的時候,返回的是IntegerCache中的陣列的值;當 i>127 或 i<-128 時,返回的是Integer類物件。
再舉一個經常被提到的例子
Integer i=100;//編譯時被翻譯成Integer i=Integer.valueOf(100);
Integer j=100;
//print true
System.out.println(i==j);
此時的 i=IntegerCache.cache[i + 128] = IntegerCache.cache[228],
同樣j = IntegerCache.cache[j + 128] = IntgerCache.cache[228]
因此 Integer引用i中儲存的是cache陣列第228號元素的地址。同理j也是同一個cache陣列的第228號元素的地址(因為cache是Integer的static陣列,只有一個)。
i==j比較的是引用地址,因此返回true。
Integer i=200;
Integer j=200;
//print false
System.out.println(i==j);
此時的 i=new Integer(200); 同樣j=new Integer(200) 。
兩次都在堆中開闢了Integer的物件。
i 和 j 中儲存的堆的物件地址是完全不同的。i==j 自然返回false。
引入快取機制的作用何在?
接著上面的例子,假如我們在程式設計時大量需要值為100(100的範圍在-128到127之間)的Integer物件。如果只能通過new來建立,需要在堆中開闢大量值一樣的Integer物件。 這是相當不划算的,IntegerCache.cache很好的起到了快取的作用。
當我們需要Integer i = 100的時候,直接從cache中取出第[100+128]號元素的地址賦值給引用i,再次需要Integer j = 100時,還是直接去這個地址賦值給j。是不是省去了在堆中不停的建立物件的代價了(空間,時間上的消耗都很大)。 這就是valueOf方法真正的提高效能之處。
正如JDK API文件對valueOf(int i)方法的描述,該方法有可能通過快取經常請求的值而顯著提高空間和時間效能。
結論
valueOf(int i)的優化只針對於範圍在-128到127的整數。
JDK1.5以後的Integer轉int
由於UnBoxing的存在,以下程式碼在JDK1.5的環境下可以編譯通過並執行。
Integer wrapperi = new Integer(0);
int i = wrapperi;
附:AutoBoxing與UnBoxing帶來的轉變
在JDK1.5之前,我們總是對集合不能存放基本型別而耿耿於懷。
以下程式碼在JDK1.5中成為了可能,試想下在JDK1.5之前該如何實現這段程式碼?
int x = 1;
Collection collection = new ArrayList();
collection.add(x);//AutoBoxing,自動轉換成Integer.
Integer y = new Integer(2);
collection.add(y + 2); //y + 2為UnBoxing,自動轉換成int。之後再次轉換為Integer。
此特性同樣適用於Map
Map map = new HashMap();
int x = 1;
Integer y = new Integer(2);
int z = 3;
map.put(x,y + z);//x自動轉換成Integer。y+z自動轉換成int。之後再次轉換為Integer。
Integer k=100;
Integer k2=100;
Integer k3=324;
Integer k4=324;
Integer s=new Integer(90);
Integer s3=new Integer(90);
int k5=100;
int k6=324;
int k7=324;
System.out.println("k==k2 "+(k==k2));
System.out.println("k3==k4 "+(k3==k4));
System.out.println("k==k5 "+(k==k5));
System.out.println("k6==k7 "+(k6==k7));
System.out.println("s==s3 "+(s==s3));
System.out.println("k3==k7 "+(k3==k7));
k2=k2.valueOf(100);
System.out.println(k2==k);
k=k.valueOf(324);
System.out.println("k==k3 "+(k==k3));
System.out.println("k==k6 "+(k==k6));
輸出結果:
k==k2 true
k3==k4 false
k==k5 true
k6==k7 true
s==s3 false
k==s false
k3==k7 true
true
k==k3 false
k==k6 true
總而言之:如果我們定義一個int型別的數,只是用來進行一些加減乘除的運算or作為引數進行傳遞,那麼就可以直接宣告為int基本資料型別,但如果要像物件一樣來進行處理,那麼就要用Integer來宣告一個物件,因為java是面向物件的語言,因此當宣告為物件時能夠提供很多物件間轉換的方式,與一些常用的方法。自認為java作為一們面向物件的語言,我們在宣告一個變數時最好宣告為物件格式,這樣更有利於你對面向物件的理解。