2013-03-13 53 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); 
     } 
    });