3

我有以下简短的自包含代码,在编译时显示错误。我拼命地试图让它编译。我通常不再遇到泛型问题,但是我放弃了这个,我请求团队的帮助。

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).

那么...我该如何修复此代码?

4

3 回答 3

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 ,此代码在运行时与问题中的代码没有什么不同。

于 2013-03-13T10:34:27.827 回答
1

我对 gontard 的解决方案玩得更多(因此,如果您对此表示赞同,请确保也对 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);
      }
  });
于 2013-03-13T14:09:19.480 回答
0

如果我们可以key转换为正确的类型

Class<T> for some T that T<:Resource<T>

那么我们就没有问题写了

ResourceType<? extends Resource<?>> result = new ResourceType<>(casted_key)

通常这种类型的转换可以通过通配符捕获来完成,但如果类型变量具有自引用绑定,则它不起作用。请参阅泛型和类的解决方法<? 扩展 Enum<?>>, EnumSet.allOf(class) 与 class.getEnumConstants()

于 2013-03-13T15:14:05.310 回答