作者: 許裕永
Java提供了與基本資料型別相對應的類別(Wrapper classes),來提供基本資料型別的進階運算。但是,在舊版的Java中,參考變數是沒有辦法像值一樣,直接放在運算式中使用的。
例:Integer i=new Integer(8);
i++;
上述範例在舊版的Java中會造成編譯錯誤,因為i是參考變數,i是代表一個物件,i所儲存的是物件代號,所以i++是無法運算的。若要運算i物件的值加1,必需寫成這樣:
i=new Integer(i‧intValue()+1);
先取得i物件的值,加1後再建構成新的物件,再指派給i。我們就會發現,在基礎運算的部份,這些類別的運算反而不如基本資料型別方便。
Autoboxing就是針對這個部份新增的功能,這個功能讓代表物件的參考變數(用Wrapper classes建構的物件),可以像一般變數一樣,直接使用於運算式之中。
對初學者而言,本章其實略看即可。因為本章敍述的細節大部份都是為了應付認證,初學者只要了解Wrapper classes的參考變數如同一般變數一樣,可以置於任意運算式之中運算就可以了。
Wrapper classes物件建構時,若用來建構物件的值,與宣告參考變數的類別是相對應的,則設計師可以不必指定建構方法,編譯器會自動將該值建構成物件後,再將物件代號指派給參考變數。
例一:
Byte b=1;
Short s=10;
Integer i=100;
Long l=1000L;
Float f=3.5F;
Double d=35.35;
Character c='a';
Boolean bo=true;
設計師不必用new來呼叫建構方法,編譯器會自動建構成物件。但是一定要注意:這個功能只限定於相對應的值與類別,若型態不符,並不會自動轉換。
在“Logn l=1000L;”這一句,若把1000L改為1000,那麼1000是int型別的值,這個值並不會先自動轉換為long型別,再來建構成物件,而是造成編譯錯誤。
在“Float f=3‧5F;”這一句,若把3‧5F改為3‧5,那麼3‧5是double型別的值,這個值並不會因為Float類別的建構方法中,有一個是可以接受double參數的,而去自動呼叫那一個建構方法,它一樣會造成編譯錯誤。
總而言之:「Autoboxing的指派功能只限定於相對應的值與類別,它不是依照類別宣告的建構方法的參數,也不會自動轉型,也不可以超過該型別的最大值或最小值的範圍」。
1-2 自動取得物件值
將物件或代表物件的參考變數置於運算式之中,編譯器會自動取得該物件的值,如同呼叫xxxValue()。此功能之專有名詞為:AutoUnboxing。
例一:
Integer i=1000;
int i2=i*2;
byte b=(byte)(i/10);
boolean bo=i>100;
以上運算式均合法。
1-3 記憶體配置
為了增加運算的效率,AutoBoxing時,如果值佔用的記憶體大小,在一個byte之內,則此物件會建構在一個專屬的記憶體範圍,在這個範圍中的物件,會重複指派給需要相同值的參考變數。(同String類別)
例一:
Integer i=8;
Integer i2=8;
System.out.println(i==i2);
此例中的Integer物件會建構在專屬記憶體範圍,在i2的敍述句執行的時候,Java不會再建構新物件,而會直接把i物件的物件代號指派給i2。所以i及i2代表同一個物件。
符合此配置機制的類別及其範圍為:
| 類別名稱 | Boolean | Character | Byte | Short | Integer |
| 值的範圍 | true/false | 0~127 | -128~127 | -128~127 | -128~127 |
例一:
Integer i=12345;
Integer i2=12345;
System.out.println(i==i2);
System.out.println(i.equals(i2));
列印結果:false true。
i與i2代表不同Integer物件,但兩個物件值均為12345。
例二:
Integer i=123;
Integer i2=123;
System.out.println(i==i2);
System.out.println(i.equals(i2));
列印結果:true true。
i與i2代表相同Integer物件。
例三:
Integer i=123;
int i2=123;
System.out.println(i==i2);
System.out.println(i.equals(i2));
列印結果:true true。
在i==i2運算時,編譯器會自動取的i物件的值與i2比對(AutoUnboxing);在i‧equals(i2)執行時,編譯器會自動把i2建構為物件再與i的物件內容做比對(AutoBoxing)。
例四:
Integer i=123;
int i2=123;
System.out.println(i2==i);
//System.out.println(i2.equals(i));
列印結果:true。
除了指派運算符號之外,參考變數無論是置於運算符號的左側或右側,均會執行AutoUnboxing。若把第四行敍述句的註解取消,則會造成編譯錯誤。因為i2不是參考變數,它不能呼叫方法。
例一:
Integer i=8;
if(i>5)
System.out.println("Hello");
列印結果:Hello。
例二:
Boolean b=true;
if(b==true)
System.out.println("Hello");
列印結果:Hello
例三:
Boolean b=true;
if(b)
ystem.out.println("Hello");
列印結果:Hello。
例一:
Scanner s=new Scanner(System.in);
System.out.print("請輸入學生成績-->");
Integer i=s.nextInt();
switch(i/10){
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
System.out.println("C");
break;
case 7:
System.out.println("B");
break;
case 8:
System.out.println("A-");
break;
case 9:
System.out.println("A");
break;
case 10:
System.out.println("A+");
break;
default:
System.out.println("請輸入正確分數");
}
本例會依照輸入的學生成績來列印等級。
例二:
Integer i=8;
switch(4*4){
case i:
System.out.printnl("Hello");
}
本例會產生編譯錯誤,因為case後必須放常數。
例三:
final Integer i=8;
switch(4*4){
case i:
System.out.println("Hello");
}
特別注意,本例還是會產生編譯錯誤,因為final宣告i為常數,是限制儲存在參考變數i中的物件代號不得變更,但不代表物件內容不能改變,所以i仍不能作為case後面的判斷值。(相關細節,後續章節還會討論)
例一:
Integer i=0;
String s="Java";
System.out.println(s.charAt(i));
列印結果:J。String類別中宣告的方法原型是void charAt(int index)。表示參數型別為int,但本例使用AutoUnboxing的功能,用Integer的物件為參數。
例二:
String s="Java";
Integer i=s.length();
System.out.println(i);
列印結果:4。String類別中宣告的方法原型是int length()。表示其運算結果為int型別,但本例使用AutoBoxing的功能,將該值建構為Integer物件。
沒有留言:
張貼留言