class ServiceLoader<S> implements Iterable<S> {
// ...
}
interface Foo<T> {
// ...
}
class FooRepository {
void add(Iterable<Foo<?>> foos) {
// ...
}
}
FooRepository repo = new FooRepository();
repo.add(ServiceLoader.load(Foo.class));
这会产生编译器错误:“FooRepository 类型中的方法 add(Iterable<Foo<?>>)
不适用于参数 (ServiceLoader<Foo>)
”。
我希望能够治疗 Iterable<Foo>
作为Iterable<Foo<?>>
,但它本身似乎不起作用。改变 ServiceLoader.load(Foo.class)
的结果的最干净的方法是什么?变成我可以喂给FooRepository.add()
的东西?
最佳答案
如果您正在谈论 java.util.ServiceLoader<S>
,然后它的 Javadoc 说:
The provider class is typically not the entire provider itself but rather a proxy which contains enough information to decide whether the provider is able to satisfy a particular request together with code that can create the actual provider on demand. [...] The only requirement enforced by this facility is that provider classes must have a zero-argument constructor so that they can be instantiated during loading.
结合使用反射明确实例化提供程序类的方式,这告诉我,使用泛型类型参数声明的提供程序类实际上将被实例化为原始类型。
因此,因为您传递的是 Class<Foo>
类型的对象-- Java 中无法构造 Class<Foo<Bar>>
类型的对象-- 那么你得到的就是你所要求的,一个 Iterable<Foo>
,其中Foo
是从 Foo<T>
创建的原始类型.
不幸的是,我认为简单的答案是:那就不要这样做!要么使您的提供程序类成为泛型类型的具体子类,要么使您的提供程序类只是一个可以构造适当泛型类型的新对象的工厂。
老实说,我想不出任何好的理由来创建一个通用的服务提供者类——你会在哪里提供类型参数?我认为工厂机制是你最好的选择。
关于java - ServiceLoader,其中类型 parm 本身是通用的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7730742/