由于Java泛型,我无法编译Guava的Cache的构建器

时间:2013-03-13 10:20:21

标签: java generics guava

我有以下简短的自包含代码,它在编译时显示错误。我拼命想要编译它。我通常不会再遇到仿制药了,但是我放弃了这个问题,并且请求团队的帮助。

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)中调用它。

那么......我该如何解决这个问题?

3 个答案:

答案 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()处的解决方法。