2015年4月6日 星期一

JAVA knowledge wild-card VS generic methods

Java 泛型提供了polymorphism更多應用, 不過實作上有wild-card ? 跟 type parameter <T> 可應用, 這兩者看起來很類似但實際上又有些應用上的不同


最近研究Scala polymorphism時候
剛好遇到Java 的wild-card VS generic methods問題
特別去網路上找下解釋
這一篇算是比較明白的解釋
http://stackoverflow.com/questions/18176594/when-to-use-generic-methods-and-when-to-use-wild-card

要明白的分辨清楚何時用wild-card or generic method

比如Collection interfave定義 這時候用wild-card ?
 interface Collection<E> {  
   public boolean containsAll(Collection<?> c);  
   public boolean addAll(Collection<? extends E> c);  
 }  

也可以用type parameter做generic method來取代
 interface Collection<E> {  
   public <T> boolean containsAll(Collection<T> c);  
   public <T extends E> boolean addAll(Collection<T> c);  
   // Hey, type variables can have bounds too!  
 }  


兩者看起來都通
但其實語意上的應用會有不同, 看一下這段介紹

This tells us that the type argument is being used for polymorphism; its only effect is to allow a variety of actual argument types to be used at different invocation sites. If that is the case, one should use wildcards. Wildcards are designed to support flexible subtyping, which is what we're trying to express here
這邊在講單純使用polymorphism,
在實際應用上根本不care不同的type parameter之間的關係時候
應該用彈性比較大的wild-card,
而且wild-card本質上就是拿來做更靈活應用的subtyping

看起來沒什麼感覺
再來看看更進一步的type parameter <T> 的解釋

Generic methods allow type parameters to be used to express dependencies among the types of one or more arguments to a method and/or its return type. If there isn't such a dependency, a generic method should not be used.
當你對type parameter使用上有特殊需求,
比如多個type parameters之間的相依性
如果沒有, 就不應該使用

到這邊
更難理解什麼是type parameter使用上有特殊需求

舉個例子
比如你今天要寫個copy method
把一個List 複製到另個List,
這個copy method要generics化, 針對任何List[T] 都可行
如果你用wild-card定義會怎樣?
 public static void copy(List<? extends Number> dest, List<? extends Number> src)  

這當然可以compile過
可是這會導致可允許傳入copy(List<String> src, List<Int> src)
你怎可以把一個List<String> 複製到 List<Int> ?
完完全全不type safe
所以說這時候src 跟desc所屬的type parameter實際上是有dependency

所以你得這樣宣告
 public static <T extends Number> void copy(List<T> dest, List<T> src)  

用<T> 來確保src跟 desc 兩者是應用到同樣的type parameter

說到這裡
wild-card跟type parameter還有其它不同處

  • 如果只有一個類型參數化的參數(one parameterized type argument, 比如說剛剛的copy只有src用type parameter,其他參數沒用) 你應該用wild-card
  • type parameter提供多重類型界定, wild-card 無法
  • wild-card有upper& lower bound,但是 type parameter只有upper bound

比如
 public void print(List<? super Integer> list) // OK  
 public <T super Integer> void print(List<T> list) // Won't compile  

對JAVA wild-card & type parameter有了解後
可以進一步看看Scala的應用


待續

沒有留言:

張貼留言