2017-02-23 40 views
0

我試圖總結(並簡化)的MapDB庫在我的項目是這樣的:正確的方法來包裝非通用類與通用的一個

 
public class MapDbPersistentStorage<V> 
{ 
    private DB db; 
    private HTreeMap<String, V> storage; 

    public MapDbPersistentStorage(String filename) 
    { 
     db = DBMaker 
       .fileDB(filename) 
       .fileMmapEnable() 
       .make(); 

     storage = (HTreeMap<String, V>) db 
       .hashMap("section", Serializer.STRING, Serializer.LONG) 
       .createOrOpen(); 
    } 

    public V get(String key, V defaultValue) 
    { 
     return storage.getOrDefault(key, defaultValue); 
    } 

    public void set(String key, V value) 
    { 
     storage.put(key, value); 
    } 

    public void close() 
    { 
     db.close(); 
    } 
} 

由於它已經指出的那樣,問題是Serializer.LONG部分(它應該是V)。我需要提供一個基於所提供的泛型類型的序列化程序。什麼是正確的做法?

+0

將'Serializer'傳遞給包裝器的構造函數。 –

+0

這並不意味着我會兩次傳遞'Long'類型嗎?曾經作爲一個通用參數,曾經作爲一個構造參數?你不認爲這是一個壞主意,因爲可以提供兩種不兼容的類型? – Mehran

+0

是的,但是你需要兩次,一次是在編譯時(泛型),另一次是在運行時(串行器)。如果你想讓它更安全,你可以將'Serializer'封裝在一個通用類型的序列化器的通用接口中,然後將該接口作爲參數。 –

回答

1

Java使用擦除來實現它的泛型。在運行時,你的類不知道你用什麼V實例化它。該信息不會在運行時保留。

所以如果你需要它在運行時,你將不得不手動保留它。但是在你當前的程序中,編譯器不知道類型Long應該如何與Serailizer.Long相關。

若要(有點)類型安全,可以將Serializer包裝在泛型類或接口中,泛型類型對應於由serialzer編碼的類型。有效地提供一種鏈接2型系統的方法。

interface GenericSerializer<T> extends Supplier<Serializer> { 

    public static GenericSerializer<Long> ofLong() { 
     return() -> Serializer.Long; 
    } 

    ... 
} 

然後在您的類:

public class MapDbPersistentStorage<V> { 
    private DB db; 
    private HTreeMap<String, V> storage; 
    private final Serializer ser; 

    public MapDbPersistentStorage(GenericSerializer<V> serFactory) { 
     this.ser = serFactory.get(); 
    } 

    public MapDbPersistentStorage(String filename) { 
     db = DBMaker 
       .fileDB(filename) 
       .fileMmapEnable() 
       .make(); 

     storage = (HTreeMap<String, V>) db 
       .hashMap("section", Serializer.STRING, ser) 
       .createOrOpen(); 
    } 

    ... 
} 

用法:

MapDbPersistentStorage<Long> m = new MapDbPersistentStorage<>(GenericSerializer.ofLong()); 

凡編譯器可以檢查GenericSerializer的類型對應的MapDbPersistentStorage的。

+0

謝謝,但這是如何消除提供'長'型兩次?您仍然將其命名爲通用參數以及構造函數參數! – Mehran

+0

@Mehran你無法解決這個問題,答案解釋了原因。至少這提供了一些編譯時檢查你是否通過了預期的'Serializer'。 –

+0

如何定義一個'私人V虛擬;'並試圖在運行時工作它的類型? – Mehran