我重新組織了一個範例。先假設沒有什麼權限或dependency的問題。先說我是用Java 8,我不知道後面版本的泛型推導有沒有變得比較智能:""(((
class Framework {
public static <T, F extends Factory<T>> T resolve(Class<F> clazz) {
try {
return clazz.newInstance().getInstance();
} catch (Exception e) {
return null;
}
}
}
abstract class Factory<T> {
abstract public T getInstance();
}
然後有一些我自己定義的interface和對應的實作與factory們
interface MyBean {}
class BeanX implements MyBean {}
class BeanY implements MyBean {}
class BeanXFactory extends Factory<BeanX> {
@Override
public BeanX getInstance() {
return new BeanX();
}
}
class BeanYFactory extends Factory<BeanY> {
@Override
public BeanY getInstance() {
return new BeanY();
}
}
接著呢,我想要幹這麼一件事,從一個list of factory class,一個一個resolve出他們對應的bean
public class GenericTest {
public static void main(String[] args) {
// 現時情況可能是想從一個file read class name然後reflection,但為了解說方便我就定一個list
final List<Class<? extends Factory<? extends MyBean>>> factoryClasses =
Arrays.asList(
BeanXFactory.class,
BeanYFactory.class
);
List<MyBean> beanList = new ArrayList<>();
factoryClasses.forEach(fc -> {
beanList.add(Framework.resolve(fc));
});
}
}
這個想法是,list那邊我下了一個Factory<? extends MyBean>
來表達我Factory create的instance一定是MyBean的實作
所以我Framework.resolve的時候每個出來的物件都會是MyBean,我就可以好好地收集起來惹
但是這個compile不會過:)))
在Java傻逼泛型下,沒有下外卡的話Generic<Children>
是不能成為foo(Generic<Parent> input)
的參數的,
泛型參數在沒有下wildcard的情況是沒做多型的
我這個的案例關鍵在Framework那裡他吃的是一個<T, F extends Factory<T>>
,這個參數F必須要是一個Factory,T要是可以直接推出來的型別
但我的list裡面的factory class們他們是Factory<? extends MyBean>,他是有bound的,所以參數要的type equality就對不起來了...
要改到過的話有兩招
-
Framework也改成吃有wildcard的
/*before*/ public static <T, F extends Factory<T>> T resolve(Class<F> clazz) /*after*/ public static <T, F extends Factory<? extends T>> T resolve(Class<F> clazz)
-
不要寫迴圈,手動展開讓他一個一個resolve...
public static void main(String[] args) { List<MyBean> beanList = new ArrayList<>(); beanList.add(Framework.resolve(BeanXFactory.class)); beanList.add(Framework.resolve(BeanYFactory.class)); }
我是覺得這很沒道理啦,我覺得Framework應該要可以推得出來T的boundary下界就是我參數的上界MyBean啊 :(
有智慧的J也是這麼覺得沒噴錯,但看來事情沒這麼簡單:(((