一般定義如下,即方法的前面加了個
public class FTest { public <t> List<t> f(T t){...}; }</t></t>
三種泛型參數推斷方式:
1、直接在f()前面加確定泛型
fTest.<integer>f(xxx)</integer>
2、透過輸入參數確定, 下面這個推斷為Integer
int number = 0; fTest.f(number)
3、可由 ##回傳值 確定
List<integer> list = fTest.f(xxx);</integer>Q: 下面這段程式碼哪裡有問題?是toString()那裡嗎?
public class A<t> { public static void test(T t){ System.out.println(t.toString()); } }</t>A:test是static方法, 因此無法感知A
需要改成
public static
A: 統一變成Object且不包含任何型別資訊。
class A<t> { void f(Object arg) if(arg instanceof T) { ... } }</t>A: 不能,編譯器會報錯。 Q: 泛型參數T可以進行new T()或new T[]操作嗎?
A: 不能,編譯器會報錯。
T.f();A: 只能呼叫Object的方法。 Q: 可以用T做強制轉換嗎?
T t = (T)object;A: 能運行, 但不會真正轉型, 編譯時會觸發waring警告。 新建泛型物件時的問題先假定有2個類, 基底類別Parent 和子類Child
class Parent{} class Child extends Parent{}回答以下問題:
Q:下面這句話有問題嗎?
List<parent> list = new ArrayList<child>()</child></parent>A:有問題,編譯就錯了。 List
List extends Parent> list = new ArrayList<child>();</child>這個list有什麼特色? A:這個list可以呼叫A a = list.get(), 但是不能list.add(new Parent())
list .get()所做的操作是在回傳時, 把內部的 extend Parent> 強轉成Parent, 是合理的,任何Parent的子類別都可以轉成Parent
list.add(new Parent ())所做的操作是在輸入時, 把外部的A轉成內部的 extend Parent>, 這是不合理的,因為我們不知道這個Parent物件可以轉成哪個Parent的子類別。
List super Child> list = new ArrayList<parent>();</parent>這個list有什麼特色?
下面誰會報錯
list.add(new Child()) list.add(new Parent()) Parent a= list.get(); Child b = list.get()A:截圖如下:
#不一定 能轉換成parent或child,所以禁止了這種行為( 例如parent的父類別是object, 但object不一定就能轉換成parent或child)。 *list.add(new Child())所做的操作是在輸入時, 把外部的child或parent轉成內部的 super Child>, 這是合理的,因為child和parent一定能轉成child的父類。
List> list = new ArrayList<a>();</a>這個list有什麼特色? A:get和add都不行,只能做remove等無回傳值無輸入A的操作。
PS: 注意,不是說不能呼叫get或add方法, 而是呼叫get或add時,不能使用A這個物件去操作。
即無法做add(A) 或 A a = get(0)
但是可以做add(object) 或Object o = get(0)
因為?可以轉為Object, 但是無法轉為A。
List<fruit> fruitList = new ArrayList(); fruitList.add(new Fruit()); List<apple> appleList = new ArrayList(); appleList.add(new Apple()); fruitList.addAll(appleList); System.out.println(fruitList);</apple></fruit>A:不會報錯。會正常列印結果。 PECS原則
注意PECS原則和上面的差異!
上面之前提到的? extend或? supert, 都是在宣告物件的時候用的。
而PECS原則是用來泛型物件的方法輸入參數!
public static class MyList<t> { List<t> list = new ArrayList(); // 把输入参数塞给自己,类似于生产操作 public void pushList(List<t> t) { list.addAll(t); } // 把自己的内容塞给输入参数,类似于让输入参数做消费。 public void pollList(List<t> t) { t.addAll(list); } }</t></t></t></t>則T就是泛型參數。 Q:下面程式碼能正常運作嗎?
MyList<number> myList = new MyList(); List<integer> intList = new ArrayList(); myList.pushList(intList); List<object> objectList = new ArrayList(); myList.pollList(objectList);</object></integer></number>A:不能正常運行, pushList和pollList都會報錯因為編譯器檢查後,認為 List
A:改成這樣:
// 把输入参数塞给自己,类似于生产操作 public void pushList(List extends T> t) { list.addAll(t); }即編譯器認為,List
A:
// 把自己的内容塞给输入参数,类似于让输入参数做消费。 public void pollList(List super T> t) { t.addAll(list); }
因为是把自己的东西塞给输入参数, 而想要能塞进去,必须保证自己这个T,是输入参数的子类,反过来说,输入参数必须是T的父类,所以用super
于是编译器认为,List
PECS原则出自Effective Java, 注意只是一个编程建议而已!
如果有一个类A,泛型参数为T
如果他一般只用于接收输入容器List后,塞入自己内部的T容器, 则类A就叫生产者, 因此输入参数最好定义为 extend T>最好, 以便能接收任何T子类的容器。
如果他一般只用于接收输入容器后List, 把自己内部的T元素塞给它, 那么这个类A就叫消费者, 输入参数最好定义为 super T>\ 最好, 以便自己的T元素能塞给任何T元素的父类容器。
以上是如何使用Java泛型方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!