关于
Java泛型,我有一个“奇怪”的问题.
首先我列出我的代码:
Service.class
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不是参数化类,而是使寄存器方法(可能是相应的查找方法)通用,那么你会更好.在您当前的方法中,ServiceProviderRegistry< Service>只能注册Service.class,而不能注册Service的任何子类.
你真正关心的是传递给寄存器的类和提供者相互匹配,这是泛型方法的理想情况.
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注释 – 如果没有完全满足编译器的方式,则无法实现此模式,编译器只能访问编译时类型.在这种情况下,您知道强制转换在运行时始终是安全的,因为寄存器是唯一修改注册表映射的东西,因此@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.