创建通用对象的缓存

时间:2018-07-29 18:46:05

标签: java generics caching

我需要创建通用对象的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>

有什么建议吗?

2 个答案:

答案 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}}类。