ServiceLoader,其中类型 parm 本身是通用的
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
不适用于参数 (ServiceLoader
”。
我希望能够将 Iterable
视为 Iterable
,但它本身似乎不起作用。将 ServiceLoader.load(Foo.class) 的结果转换为可以提供给 FooRepository.add() 的最干净的方法是什么?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您正在谈论
java.util。 ServiceLoader
,那么它的 Javadoc 说:结合使用反射明确实例化提供程序类的方式,这告诉我使用泛型类型参数声明的提供程序类实际上将被实例化为原始类型。
因此,因为您传递的是
Class
类型的对象,而 Java 中无法构造Class>
类型的对象。 code> —— 那么你得到的就是你所要求的,一个Iterable
,其中Foo
是从创建的原始类型Foo
。不幸的是,我认为简单的答案是:那就不要这样做!要么使您的提供程序类成为泛型类型的具体子类,要么使您的提供程序类只是一个可以构造适当泛型类型的新对象的工厂。
老实说,我想不出任何好的理由来创建一个通用的服务提供者类——你会在哪里提供类型参数?我认为工厂机制是你最好的选择。
If you're talking about
java.util.ServiceLoader<S>
, then its Javadoc says:Combined with the way that the provider class is clearly instantiated using reflection, that tells me that a provider class declared with a generic type argument will in fact be instantiated as a raw type.
Thus, because you're passing in an object of type
Class<Foo>
-- and there's no way in Java to construct a object of typeClass<Foo<Bar>>
-- then what you get back is what you asked for, anIterable<Foo>
, whereFoo
is the raw type created fromFoo<T>
.Unfortunately, I think the simple answer is: Don't do that then! Either make your provider class be a concrete subclass of the generic type, or else make your provider class be simply a factory that can construct new objects of the appropriate generic type.
Honestly, I can't think of any good reason to make a generic service provider class anyway -- where would you provide the type arguments? I think the factory mechanism is your best bet.
这是因为泛型类型仅用于编译时。它们在运行时被擦除(类型擦除)。 Foo 接口的泛型类型 T 在运行时将不再为人所知,因此 Repo 类的“add”方法不会让您进一步(一般)输入参数类型(不会让您拥有
Foo
,因为它不能保证在方法内部您能够实际将该参数视为F
类型的参数。只知道它的类型 它不会让您进一步输入它。Foo,因为这是一个实际类型,但如果您将方法更改为
void add(Iterable foos)
,That's because generic types are for compile time only. They are erased at runtime (type erasure). The generic type T of the Foo interface will no longer be known at runtime, so the "add" method of the Repo class will not let you further (generically) type the argument type (will not let you have the argument of type
Foo<?>
, since it can't guarantee that inside the method you'll be able to actually treat that argument as an argument of typeF<?>
. It only knows that it's of type Foo, because that's an actual type, but it won't let you generically type it further. Your code will run if you change the method tovoid add(Iterable<Foo> foos)
这一切都归咎于 Java 的类型系统。你需要残酷的演员阵容。
将
Foo.class
转换为Class>
,或将ServiceLoader
转换为ServiceLoader ?>>
。两者显然都是无害的。The blame falls on Java's type system. You need brute cast.
Either cast
Foo.class
toClass<Foo<?>>
, orServiceLoader<Foo>
toServiceLoader<Foo<?>>
. Both are obviously harmless.