繁体   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