我有以下简短的自包含代码,它在编译时显示错误。我拼命想要编译它。我通常不会再遇到仿制药了,但是我放弃了这个问题,并且请求团队的帮助。
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
public class CacheWithGenericsDoesNotCompile {
// Class definition can't be modified
static class Resource<T extends Resource<T>> {}
// Class definition can't be modified
static class ResourceType<T extends Resource<T>> {
public ResourceType(Class<T> type) {}
}
// Variable definition may be modified
static LoadingCache<Class<? extends Resource<?>>, ResourceType<? extends Resource<?>>> cache = CacheBuilder.newBuilder().build(
new CacheLoader<Class<? extends Resource<?>>, ResourceType<? extends Resource<?>>>() {
@Override public ResourceType<? extends Resource<?>> load(Class<? extends Resource<?>> key) throws Exception {
return new ResourceType<? extends Resource<?>>(key);
}
});
// Method definition can't be modified, method content may.
@SuppressWarnings("unchecked")
static <T extends Resource<T>> ResourceType<T> getResourceType(Class<T> type) {
return (ResourceType<T>)cache.getUnchecked(type);
}
}
无法编译的行是:
return new ResourceType<? extends Resource<?>>(key);
我知道它失败的原因:我可能不会用问号(new Xxxx<...>
)写?
。我不能以不同方式编写这一行来编译其他行。
在Resource
没有泛型的情况下,我有一个后备解决方案,但在可能的限制内,我希望Resource
使用泛型。
我对LoadingCache
的泛型没有限制,只是我需要在getResourceType(Class)
中调用它。
那么......我该如何解决这个问题?
答案 0 :(得分:5)
有一些忽略警告的解决方案:
static LoadingCache<Class<? extends Resource<?>>, ResourceType<? extends Resource<?>>> cache = CacheBuilder.newBuilder().build(
new CacheLoader<Class<? extends Resource<?>>, ResourceType<? extends Resource<?>>>() {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override public ResourceType<? extends Resource<?>> load(Class<? extends Resource<?>> key) throws Exception {
return new ResourceType(key);
}
});
正如@John B在评论中所建议的那样。由于type-erasure,此代码在运行时上的代码与问题中的代码没有区别。
答案 1 :(得分:1)
我使用gontard的解决方案玩了一些(所以如果你赞成这个,请确保upvote gontard的答案)和millimoose的评论。我找到了这个完全删除泛型的解决方案,以获得更易读的代码。
@SuppressWarnings("rawtypes")
static LoadingCache<Class, ResourceType> cache = CacheBuilder.newBuilder().build(
new CacheLoader<Class, ResourceType>() {
@SuppressWarnings("unchecked")
@Override public ResourceType load(Class key) throws Exception {
return new ResourceType(key);
}
});
答案 2 :(得分:0)
如果我们可以将key
转换为正确的类型
Class<T> for some T that T<:Resource<T>
那么我们写没有问题
ResourceType<? extends Resource<?>> result = new ResourceType<>(casted_key)
通常这种类型的转换可以通过通配符捕获来完成,但是如果类型变量具有自引用绑定,则它不起作用。请参阅Generics and Class<? extends Enum<?>>, EnumSet.allOf(class) vs class.getEnumConstants()处的解决方法。