我需要创建通用对象的Java缓存。我正在尝试执行以下操作,但这将无法编译。
public class Example<T> {
public static class ExampleCache {
private Map<String, Example<?>> cache = new ConcurrentHashMap<>();
public <T> Example<T> getExample(String name) {
return cache.computeIfAbsent(name, k -> new Example<T>());
}
}
}
具有cache.computeIfAbsent的行会生成错误
"Error:(16, 35) java: incompatible types: Example<capture#1 of ?> cannot be converted to Example<T>
有什么建议吗?
答案 0 :(得分:0)
发生这种情况是因为类型T
与通配符?
不兼容。编译器如何才能知道将从值Example<T>
的映射中收到Example<?>
?您必须使用强制转换或更好地将类型应用于静态类:
public class Example<T> {
public static class ExampleCache<T> {
private Map<String, Example<T>> cache = new ConcurrentHashMap<>();
public Example<T> getExample(String name) {
return cache.computeIfAbsent(name, k -> new Example<>());
}
}
}
如果您不将类型包括在ExampleCache
中,则会引发错误:
无法静态引用非静态类型T
这仅在ExampleCache
不是static
的情况下有效,但是ExampleCache
的实例将固定为Example<T>
的实例。有关更多信息,请阅读Java generics with class and nested static interface。
答案 1 :(得分:0)
您尝试执行的操作不是安全键入。
您可以将?
强制转换为T
,但输入的类型不安全:
return (Example<T>) cache.computeIfAbsent(name, k -> new Example<T>());
您希望getExample()
的客户端决定返回的Exemple
实例的通用类型。
假设您添加为条目"hello"-"Example<String>"
,并且客户端以这种方式调用getExample()
:Example<Integer> example : getExample("hello");
,则他/她将具有不正确的泛型类型,并且可能在运行时引发一些不一致/异常。
实际上ExampleCache
与作为输入/输出的通用类型不一致。
因此,要么用T
替换通配符以定义特定类型的ExampleCache
,要么像在客户端类中那样仅在缓存中使用Example<?>
,或者仍然不对{{ 1}}类。