簡體   English   中英

Java中的泛型方法的遞歸調用

[英]Recursive call with Generic method in Java

我正在處理如下的舊代碼

public Map myMethod(Map arg){
      Map newMap = createMap(); //This method creates a new Map instance.
      Iterator entries = arg.entrySet().iterator();
      while (entries.hasNext()) {
          Entry thisEntry = (Entry) entries.next();
          Object key = thisEntry.getKey();
          Object value = thisEntry.getValue();

          if ( value instanceof Map){
               Map newElement = myMethod((Map)value); // Recursive call here
               newMap.put(key, newElement);
          }else if ( value instanceof String ){
               newMap.put(key, value);
          }
      }
      return newMap;
}

顯然,我想改編泛型。 所以我改變了方法,

public <K,V> Map<K,V> myMethod(Map<K,V> arg){
      Map<K,V> newMap = createMap(); //creates a new Map instance.
      for ( Entry<K,V> entry : arg.entrySet()){

          K key = entry.getKey();
          V value = entry.getValue();

          if ( value instanceof Map){
               V newElement = myMethod(value); // Recursive call here
               newMap.put(key, newElement);
          }else if ( value instanceof String ){
               newMap.put(key, value);
          }
      }
      return newMap;
}

我的問題是關於遞歸調用的行。 到目前為止,我已經嘗試過

  1. V newElement = myMethod(value); ->編譯錯誤
  2. Map<K,V> newElement = myMethod(value); ->編譯錯誤
  3. V newElement = (V) myMethod((Map<?,?>)value); ->輸入安全警告

---------編輯----------

我可以做的進一步假設是

  1. createMap()方法可以更改為createMap(arg)
  2. arg的元素類型不限於特定的Java類型。 這是一種庫方法,因此必須是通用的

代碼的邏輯不是類型安全的,因此無法避免類型安全警告。

您可以使用createMap()創建一個新地圖; 該方法正在盲目創建新地圖,沒有任何信息,因此它創建的地圖類不必與傳入的arg類相同。這意味着您的方法myMethod()返回的地圖不一定是與傳入的類相同的實現類。

在遞歸調用中,您將一個我們知道是V的實例的映射傳遞到遞歸調用中,並且您希望返回的對象是V 但這不一定是正確的。 例如,如果VTreeMap ,而遞歸調用返回的是HashMap呢? 這樣它就不能轉換為V ,並且您不可能從中安全地獲得V

您的類型都在這里弄亂了。

您的方法需要

Map<K,V> 

並返回一個

Map<K,V>

那意味着電話

V newElement = myMethod(element); 

一定是

Map<K,V> newElement = myMethod(element);  //element is of type Map<K,V>

和電話

newMap.put(key, newElement);

表示newElement也必須為V類型。

因此,您基本上都需要String,Map和V來具有某種通用的超級類型。 在原始代碼中,Map實際上是

Map<Object, Object>

所以超級類型是Object。

我會備份並問自己,為什么您有一個同時存儲Maps和Strings的映射。 您可能應該將它們重構為實際代表其類型的對象。

例如,假設它是一個文件系統,而Map是一個目錄,而String是一個文件,那么您實際上應該創建一個既可以是目錄也可以是文件的FileObject,並且您的方法簽名變為:

Map<K, FileObject> myMethod(Map<K, FileObject> map)

暫無
暫無

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

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