|
|
如果你需要持有一組物件,在Java中,你應該會選擇使用Collection相關類別,例如: List list = new ArrayList(); list.add("字串物件一"); list.add("字串物件二"); Collection或Map的實作類別,允許你持有不同類型的物件,不過絕大多數的情況下,你所需持有的物件是同一種物件。Collection或Map是使用Object型態來持有物件,如果你需要取回物件,你必須記得當初放入的物件類型,並且: String str = (String) list.get(0); 這是在JDK1.4之前的情況,如果你搞錯型態,將會發生ClassCastException。 當你在JDK5之後的版本下編譯以上的程式碼,將會出現警示訊息: Note: Test.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 遵照指示,重新加上-Xlint:unchecked進行編譯,你會看到: Test.java:5: warning: [unchecked] unchecked call to add(E) as a member of the ra w type java.util.List list.add("字串物件一"); ^ Test.java:6: warning: [unchecked] unchecked call to add(E) as a member of the ra w type java.util.List list.add("字串物件二"); ^ 2 warnings 警示訊息不是錯!編譯器在告訴你,你有個操作可能不安全,將來可能發生ClassCastException。它有更好的功能,也許你可以試試。例如: List<String> list = new ArrayList<String>(); list.add("字串物件一"); list.add("字串物件二"); String str = list.get(0); 這次加上了角括號,並在角括號中指定將持有之物件類型,當從List中取回物件時,也不再需要轉型,將這個程式片段編譯,編譯器不再出現警示訊息,這是JDK5之後新增的Generic功能。 實際上,如果你反組譯程式,會發現這又是編譯器提供的蜜糖功能之一。 ArrayList arraylist = new ArrayList(); arraylist.add("\u5B57\u4E32\u7269\u4EF6\u4E00"); arraylist.add("\u5B57\u4E32\u7269\u4EF6\u4E8C"); String s = (String)arraylist.get(0); 跟你原來沒有Generic時所作的一樣。在JDK5之後,Collection與Map所有實作類別,都以Generic改寫過了。正如先前所說的,其實絕大多數的情況下,你所持有的物件都會是同一類型,藉由Generic語法,以及編譯器的展開,可以在編譯時期就作好型態檢查動作,避免ClassCastException的發生。 你可以自行定義Generic類別,例如: public class Some<T> {並且這麼使用它: Some<String> some = new Some<String>(); some.setThing("some thing"); String something = some.getThing(); 實際上,當你反組譯Some.class時,會發現: public class Some { public Some() { } public void setThing(Object obj) { thing = obj; } public Object getThing() { return thing; } private Object thing; } 在JDK1.4之前,若想進行Generic的類別定義,正是使用Object來持有型態,並且再取回之後進行轉型的動作,將物件轉為正確的型態。反組譯使用Some的那段程式碼,發現也是這麼作的: Some some = new Some(); some.setThing("some thing"); String s = (String)some.getThing(); JDK5之後的Generic語法,還可以限制可指定之類型,例如: import java.io.*; 如果你反組譯這段程式碼,會發現其中的神秘: import java.io.Serializable; public class Some { public Some() { } public void setThing(Serializable serializable) { thing = serializable; } public Serializable getThing() { return thing; } private Serializable thing; } 當 然!編譯器提供的語法展開等功能,讓你可以直接使用角括號來撰寫Generic語法,實際上編譯出的.class檔案,還會有額外的Generic資訊, 這些資訊讓使用該類別的程式片段在編譯時,可為編譯器所用。因此,若程式使用了Generic資訊,你的.class將無法使用於JDK1.4而更之前的 版本。 如果你真的要在Collection等中放入不同型態的物件呢? public void do() { List list = new ArrayList(); list.add("Some"); list.add(new Date()); ... } 如果不想編譯器出現惱人的警示訊息,則加上個@SuppressWarnings可以解決問題: @SuppressWarnings(value={"unchecked"}) public static void main(String[] args) { List list = new ArrayList(); list.add("Some"); list.add(new Date()); } |