我有一个关于 Java 泛型的“奇怪”问题。
首先我列出我的代码:
服务类
package jse.generics.service;
public interface Service {
}
ServiceProvider.class
package jse.generics.service;
public interface ServiceProvider<T extends Service> {
public T getService();
}
ServiceProviderRegistry.class
package jse.generics.service;
import java.util.HashMap;
import java.util.Map;
public class ServiceProviderRegistry<T extends Service> {
private Map<Class<T>, ServiceProvider<T>> map = new HashMap<Class<T>, ServiceProvider<T>>();
public void register(Class<T> clazz, ServiceProvider<T> provider) {
map.put(clazz, provider);
}
}
FooService.class
package jse.generics.service;
public class FooService implements Service {
}
FooServiceProvider.class
package jse.generics.service;
public class FooServiceProvider implements ServiceProvider<FooService> {
@Override
public FooService getService() {
return new FooService();
}
}
ServiceTest.class
package jse.generics.service;
public class ServiceTest {
/**
* @param args
*/
public static void main(String[] args) {
ServiceProviderRegistry<? extends Service> registry = new ServiceProviderRegistry<Service>();
registry.register(FooService.class, new FooServiceProvider());
}
}
在 ServiceTest 类中,编译器提示 registry.register 方法不适用于传递给它的参数。我真的不知道为什么会这样。所以我期待着你们的帮助来解决这个问题。
最佳答案
在这种情况下,如果 ServiceProviderRegistry
会更好不是参数化类,而是使 register
方法(可能还有相应的查找方法)泛型。在您当前的方法中 ServiceProviderRegistry<Service>
只能注册Service.class
,而不是服务的任何子类。
您真正关心的是传递给 register
的类和提供程序相互匹配,这是泛型方法的理想情况。
public class ServiceProviderRegistry {
private Map<Class<?>, ServiceProvider<?>> registry = new HashMap<>();
public <T extends Service> void register(Class<T> cls, ServiceProvider<T> provider) {
registry.put(cls, provider);
}
@SuppressWarnings("unchecked")
public <T extends Service> ServiceProvider<T> lookup(Class<T> cls) {
return (ServiceProvider<T>)registry.get(cls);
}
}
您将需要 @SuppressWarnings
注释——如果没有一种完全满足编译器的方式,就不可能实现这种模式,编译器只能访问编译时类型。在这种情况下,您知道转换在运行时始终是安全的,因为 register
是唯一修改 registry
的东西 map ,所以 @SuppressWarnings
是有道理的。 Jon Skeet's answer to this related question总结得很好
Sometimes Java generics just doesn't let you do what you want to, and you need to effectively tell the compiler that what you're doing really will be legal at execution time.
关于Java 泛型类的方法不适用于传递的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16979014/