簡體   English   中英

Java Generics:通用映射(深層副本)的方法簽名

[英]Java Generics: method signature for (deep copy of) generic Maps

我有一些Map ,它們本身可能再次包含Map (任何類型)。 我用簽名寫了一個方法:

public static <K,V> HashMap<K,V> deepCopyHashMap(HashMap<K,V> s);

但是,我現在想概括一下這個代碼以支持Map ,但仍返回與參數類型相同的對象。 所以代替:

public static <K,V> HashMap<K,V> deepCopyHashMap(HashMap<K,V> s);
public static <K,V> CheckedMap<K,V> deepCopyCheckedMap(CheckedMap<K,V> s);
public static <K,V> TreeMap<K,V> deepCopyTreeMap(TreeMap<K,V> s);
...
etc.

我想要這樣的東西:

public static <K,V, M extends Map<K,V>> M<K,V> deepCopyMap(M<K,V> s);

但是,這給了我:

Multiple markers at this line
- The type M is not generic; it cannot be parameterized with arguments <K, 
 V>
- The type M is not generic; it cannot be parameterized with arguments <K, 
 V>

如何正確聲明方法簽名並仍然返回正確類型的對象(不使用內部反射)?

對於這個項目,添加更多依賴項實際上不是一個選項,所以我更喜歡不依賴於外部庫的解決方案。 此外,我已經研究了Cloneable接口,但是它只是一個標記接口(一般沒有Map的實現),對我來說沒有多大用處。


編輯:作為參考,這是我深層復制嵌套HashMap的代碼(代碼正常工作):

public static <K,V> HashMap<K,V> deepCopyHashMap(HashMap<K,V> source){
    HashMap<K,V> result = new HashMap<K, V>();
    for(Map.Entry<K, V> entry : source.entrySet()){
        K k = entry.getKey();
        V v = entry.getValue();
        if(k instanceof HashMap<?,?>){
            k = (K) deepCopyHashMap((HashMap<?,?>) k);
        }
        if(v instanceof HashMap<?,?>){
            v = (V) deepCopyHashMap((HashMap<?,?>) v);
        }
        result.put(k, v);
    }
    return result;
}

編輯:解決方案

  1. 這不是一個理想的解決方案。如果沒有嵌套Map的運行時類型的默認構造函數,它將失敗。 我已經使用嵌套的HashMap對其進行了測試,並且正確地復制了運行時類型。

     @SuppressWarnings("unchecked") public static <K,V, M extends Map<K,V>> M deepCopyMap(M source) throws InstantiationException, IllegalAccessException{ M result = (M) source.getClass().newInstance(); for(Map.Entry<K, V> entry : source.entrySet()){ K k = entry.getKey(); V v = entry.getValue(); if(k instanceof Map<?,?>){ k = (K) deepCopyMap((Map<?,?>) k); } if(v instanceof Map<?,?>){ v = (V) deepCopyMap((Map<?,?>) v); } result.put(k, v); } return result; } 
  2. 這樣更安全,但需要明確列出所有已知類型:

     @SuppressWarnings("unchecked") public static <K,V, M extends Map<K,V>> M deepCopyMap(M source){ M result; if(source instanceof HashMap){ result = (M) new HashMap<K,V>(); } else { //fail } // etc. add more types here for(Map.Entry<K, V> entry : source.entrySet()){ K k = entry.getKey(); V v = entry.getValue(); if(k instanceof Map<?,?>){ k = (K) deepCopyMap((Map<?,?>) k); } if(v instanceof Map<?,?>){ v = (V) deepCopyMap((Map<?,?>) v); } result.put(k, v); } return result; } 

通用類型參數不能是自己的通用。 只需刪除M的通用定義:

public static <K, V, M extends Map<K, V>> M deepCopyMap(M s);

您聲明的通用定義M<K, V>已經是隱含的,因為編譯器必須確保M extends Map<K, V>為真。 因此,定義M<K, V>是多余的。

至於在方法內部創建副本,它變得更加復雜。 通用類型改進了通用方法的用戶的類型安全性。 但是,在方法內部,您就像使用非泛型方法一樣無能為力,該方法將原始Map作為其參數。 (你當然可以進一步重寫通用類型。)

畢竟,我不建議你采用你建議的方法。 您建議您的API用戶可以深度克隆作為方法參數提供的任何類型的Map 但是,你做不到。 Map是一個公共接口,任何人都可以實現它。 在運行時,您可能會被要求創建一個您不知道的深度克隆映射,您將無法做到。 看看這個實現:

@SupressWarnings("unchecked")
public static <K, V, M extends Map<K, V>> M deepCopyMap(M s) {
    Map map;
    if(s.getClass() == HashMap.class) {
      map = new HashMap();
    } else if(s.getClass == LinkedHashMap.class) {
      map = new LinkedHashMap();
    } else {
      throw new RuntimeException("unknown map type " + s.getClass());
    }
    for(Map.Entry<K, V> entry : source.entrySet()) {
        K k = entry.getKey();
        V v = entry.getValue();
        if(k instanceof Map) {
          map.put(k, deepCopyMap((Map) k));
        } else {
          result.put(k, v);
        }
    }
    return (M) map;
}

這對用戶來說不是很普遍,如果地圖包含一些用戶類型地圖,很可能會拋出異常。 編譯器會在這種方法中警告你幾乎任何事情的事實是一個好跡象,這是一個壞主意。

相反,我實際上會建議你重載方法,你只為已知類型提供深度克隆。 但是,如果您發現了無法在運行時創建的嵌套映射,則必須拋出運行時異常。 您正在尋找的那種類型安全很難實現。 另外,我會將它作為合同的隱含部分,您不能使用嵌套映射,其中映射類型不在指定的Map實現組中。

旁注:在不限制MV ,定義這些參數沒有意義,因為您對這些參數一無所知。 只需使用通配符?

您定義的類型M已經綁定為Map<K,V>其中<K, V, M extends Map<K, V>> 所以只需刪除M<K,V>然后將其M

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM