2013-03-13 54 views
3

我有以下简短的自包含代码,它在编译时显示错误。我拼命尝试编译它。我通常不再对泛型有任何疑问,但是我放弃了这一点,并且请求团队的帮助。由于Java泛型,我无法编译Guava的Cache构建器

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

啊,我所缺少的是递归边界('T extends Resource ')被通配符捕获的局限性所迷失,这就是为什么我的答案不起作用。 – 2013-03-13 12:23:10

回答

5

一些忽略警告:A液

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的问题中的代码。

+3

作为补充一点,上面的代码在运行时没有问题,因为类型擦除,所以没有理由不使用它。 – 2013-03-13 10:38:22

+0

是的,它编译和完成这项工作。谢谢! – 2013-03-13 11:06:26

+2

与原始类型一样令人讨厌,它们在这里可能是一个可以接受的方法。为了缓存是静态类型安全的,它需要泛型系统根本无法表达的键和值之间的约束,因此“不使用”泛型是有意义的。 – millimoose 2013-03-13 12:30:51

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); 
     } 
    });