静态方法引用泛型类型解

时间:2018-01-09 13:31:25

标签: java generics lambda casting java-8

我知道此类问题已经发布过,但即使在检查完所有链接后,我也无法找到解决我所面临问题的方法。以下是我拥有的以及我希望它做的事情:

@FunctionalInterface
public interface ProcessExecute {
    <K, T> K executeProcess(T arguments);
}

一个简单的函数接口(因此它可以表示为lambda),它接受一个T参数(意味着你可以赋予它不同的参数)和一个K返回类型,这意味着它将返回一个K对象。接下来,我有这个:

public interface ProcessHandler {

   void initializeMap();

   Process retrieveProcess(String key,Object parameters);

   <K, T> K executeProcess(String key,T parameters);

   <K> K executeProcess(String key);

}

为了解释有意义,在上面的接口的实现中,我有一个HashMap,它将String键链接到ProcessExecute项。所以ProcessHandler应该简单地将String作为键,在map中找到它,然后在map中找到的对象上调用ProcessExecute :: executeProcess方法,然后返回需要返回的内容(由参数类型指定) 。基本上,ProcessHandler中的executeProcess与ProcessExecute中的executeProcess相同。现在,我对ProcessHandler有以下实现:(由于类很大,我只会提供一个样本,但它就足够了)

public class ProcessManager implements ProcessHandler {
   private static final Map<String, ProcessExecute> processMap = new HashMap<>();
   private static final ProcessHandler instance = new ProcessManager();

   public static ProcessHandler getInstance() {
      return instance;
   }
   //many other methods identical to executeRam (that return boolean/String/int and take String or other types as arguments
   private static Process executeRam(Void arguments) {
      Process ram = null;
      try {
          ram = new ProcessBuilder("free", "m").start();
      } catch (IOException e) {
          Log.printLog(TAG.ERROR, "Unable to run free -m command!");
      }
      return ram;
  }

  @Override
  public void initializeMap() {
  //many other declarations identical to this one
    ProcessExecute ramMonitor =ProcessManager::executeRam;
    processMap.put("ram", ramMonitor);
  }

  @Override
  public Process retrieveProcess(String key, Object arguments) {
      return (Process) processMap.get(key).executeProcess(arguments);
 }


  @Override
  public <K, T> K executeProcess(String key, T parameters) {
      return processMap.get(key).executeProcess(parameters);
  }

  @Override
  public <K> K executeProcess(String key) {
      return processMap.get(key).executeProcess(null);
  }

}

问题出在initializeMap()方法的编译中:将项目声明为

ProcessExecute xxx = ProcessManager:executeXXX;

它报告方法引用中的错误返回类型:无法将java.lang.Process转换为K (这是特定于executeRam方法,但它扩展到所有其他方法,当然,例如。无法转换java.lang.String等。)

我做错了什么?需要改变什么才能编译?为了澄清我希望它在该类中做什么,我想在ProcessManager中调用executeProcess(String键,T参数)时,要在HashMap中搜索该键,然后执行该项(这是一个ProcessExecute) executeProcess方法,并为它正确推断类型(因为它们中的许多返回null或boolean或字符串或整数,并作为参数不同类型,如上所述),并且,对于我的生活,我无法弄清楚在哪里是我逻辑上的错。

让我更进一步困惑的是,我设法为这个问题找到了一个(奇怪的?)解决方案,但我不想实现它,因为我根本不明白为什么它有效,所以如果你可以请给我亲自了解为什么以下工作以及如何改进或改变它,请执行此操作。基本上,如果我将executeRam方法更改为:

private static <K, T> K executeRam(T arguments) {
  Process ram = null;
  try {
      ram = new ProcessBuilder("free","m").start();
  } catch (IOException e){
      Log.printLog(TAG.ERROR,"Unable to run free -m command!");
  }
  return (K) ram;
}

然后它将在initializeMap()方法中没有错误(它实际上有效)。但是回归K(?)似乎有点怪异和笨拙。此外,这种改变所有其他方法的解决方案并不完整:在我的具有原始返回类型(如布尔值)的方法上,它会抱怨它无法将布尔值强制转换为K,因此我无法使我的解决方案适应其他方法。

1 个答案:

答案 0 :(得分:2)

你在这里遇到的问题是你在方法上声明了类型变量。

public interface ProcessExecute {
    <K, T> K executeProcess(T arguments);
}

表示您可以将任何传递给该方法,并希望能够获得任何类型的任何类型。

ProcessExecute pex = ...;
String s = pex.executeProcess(1);
Integer i = pex.executeProcess("");

这会在您调用时产生ClassCastException,除非您将结果用作Object(如Object obj = pex.execute("");),或者从null返回public interface ProcessExecute<K, T> { K executeProcess(T arguments); } 方法。

相反:

ProcessExecute

意味着,给定ProcessExecute<Void, Process> ramMonitor = ProcessManager::executeRam; Process p = ramMonitor.executeProcess(null); 的实例,您总是必须传入相同的参数类型,并且您将始终返回相同的参数。

然后您可以像这样使用此实例:

ID-Final_RDX_301_002-14_33_1992

Area code is 301
house number is 002

ID-Final_RDX-311-004-14_28_1992

Area code is 311
house number is 004

ID-Final_RDX311021-14_28_1992

Area code is 311
house number is 021

ID-Final_RDX-XT-Se3-14_28_1992

Area code is XT
house number is Se3

ID-Final_RDX-XT-Se11-14_28_1992

Area code is XT
house number is Se11