我有以下设置。我有一个由AbstractFetcher<T>
实施的StringFetcher
。然后我有一个工厂根据输入返回AbstractFetcher
..这里OneClass
正在使用AbstractFactoryFetcher
。在方法doSomething
中,我得到第二行的编译器错误,但不是第一行!换句话说,fetchMany()
编译得很好!这是怎么回事?即使使用通用方法提示,如何更改签名,以便不需要进行转换?我的最终目标是将OneClass与关于具体获取者的知识分离,以便即使FetcherFactory上有更改也可以单独部署/编译。
public interface AbstractFetcher<T> {
T fetchOne();
List<T> fetchMany();
}
public class StringFetcher implements AbstractFetcher<String> {
@Override
public String fetchOne() {
return "a string"
}
@Override
public List<String> fetchMany() {
List<String> list = new ArrayList<>();
list.add("String 1");
list.add("String 2");
return list;
}
}
public interface AbstractFactoryFetcher {
public AbstractFactoryFetcher make(String type);
}
public class FetcherFactory implements AbstractFactoryFetcher {
public AbstractFetcher make(String type) {
if (type.equals("String")) {
return new StringFetcher();
}
else {
return null;
}
}
}
public class OneClass {
FetcherFactory factory;
public OneClass(FetcherFactory factory) {
this.factory = factory;
}
public void doSomething() {
List<String> list = factory.make("String").fetchMany();
String one = factory.make("String").fetchOne(); //compiler error Required: String, Found: Object
}
}
谢谢!
答案 0 :(得分:1)
您在AbstractFetcher
中使用doSomething
作为原始类型,这意味着使用了它的方法的擦除:
Object fetchOne();
List fetchMany();
虽然List
可以转换为List<String>
(带有未经检查的警告)。对象无法转换为String
。
最好是你有一个强类型的工厂:
public AbstractFetcher<String> makeStringFetcher() {
return new StringFetcher();
}
您尝试将返回值用作AbstractFetcher<String>
,这意味着您在编译时以任何方式知道type
字符串。
泛型是一个编译时间,编译器无法知道type
字符串的运行时值。因此,在这种情况下,您不能拥有通用类型安全性。
答案 1 :(得分:1)
但是在工厂里还有一个铸件:
public class FetcherFactory {
public <T> AbstractFetcher<T> make(Class<T> type) {
if (type.equals(String.class)) {
return (AbstractFetcher<T>) new StringFetcher();
}
else {
return null;
}
}
}
然后你可以这样打电话:
public void doSomething() {
List<String> list = factory.make(String.class).fetchMany();
String one = factory.make(String.class).fetchOne();
}
答案 2 :(得分:1)
如果您可以将Class<X>
而不是字符串参数传递给工厂,那么有一种方法可以在不进行任何强制转换的情况下实现此目的,但需要反射才能使其正常工作。
像这样实施FetcherFactory
:
public class FetcherFactory {
public <T, U extends AbstractFetcher<T>> AbstractFetcher<T> make(Class<U> type) {
try {
return type.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
然后您可以在呼叫网站上使用它,如下所示:
public class OneClass {
FetcherFactory factory;
public OneClass(FetcherFactory factory) {
this.factory = factory;
}
public void doSomething() {
List<String> list = factory.make(StringFetcher.class).fetchMany();
String one = factory.make(StringFetcher.class).fetchOne();
}
}