简体   繁体   English

静态方法参考泛型类型解决方案

[英]Static method reference generic type solution

I am aware that this type of question has been posted before but even after checking all the links I could not come up with a solution for the problem that I am facing. 我知道这种类型的问题已经发布过,但是即使在检查了所有链接之后,我也无法针对我所面临的问题提出解决方案。 Here is what I have and what I want it to do: 这是我所拥有的以及我想要它做的:

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

A simple functional interface (so that it can be expressed as lambda) that takes a T argument (meaning you can give different arguments to it) and a K return type, meaning it will return a K object. 一个简单的函数接口(以便可以将其表示为lambda),它带有一个T参数(意味着可以为其提供不同的参数)和一个K返回类型,这意味着它将返回一个K对象。 Next, I have this: 接下来,我有这个:

public interface ProcessHandler {

   void initializeMap();

   Process retrieveProcess(String key,Object parameters);

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

   <K> K executeProcess(String key);

}

For the explanation to make sense, in the implementation of the above interface I have a HashMap that links a String key to a ProcessExecute item. 为了使说明有意义,在上述接口的实现中,我有一个HashMap,它将String键链接到ProcessExecute项。 So the ProcessHandler should simply take a String as a key, finds it in the map, then calls the ProcessExecute::executeProcess method on that object found in the map, and then it returns what needs to be returned (specified by the parameter type). 因此,ProcessHandler应该仅将String作为键,在映射中找到它,然后对映射中找到的对象调用ProcessExecute :: executeProcess方法,然后返回需要返回的内容(由参数类型指定) 。 Basically, the executeProcess in the ProcessHandler is the same as the one in the ProcessExecute. 基本上,ProcessHandler中的executeProcess与ProcessExecute中的executeProcess相同。 Now, I have the following implementation for the ProcessHandler: (I will only put a sample of it since the class is quite big, but it will suffice) 现在,我为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);
  }

} }

The problem is at compilation in the initializeMap() method : When declaring an item as 问题是在initializeMap()方法中进行编译时:将项目声明为

ProcessExecute xxx = ProcessManager:executeXXX; ProcessExecute xxx = ProcessManager:executeXXX;

it reports that Bad return type in method reference:can not convert java.lang.Process to K (this is specific for the executeRam method, but it extends to all other methods, of course, eg. can not convert java.lang.String and so on). 它报告方法引用中的错误返回类型:无法将java.lang.Process转换为K (这特定于executeRam方法,但是它扩展到了所有其他方法,例如,不能转换java.lang.String等等)。

What am I doing wrong? 我究竟做错了什么? What needs to be changed so that it can be compiled? 需要更改哪些内容才能进行编译? To clarify what I want it to do in that class, I want when calling the executeProcess(String key, T parameters) in the ProcessManager, for it to search for that key in the HashMap, then execute that item's (which is a ProcessExecute) executeProcess method and for it to correctly infer the types (since many of them return null or boolean or Strings or Integers and take as arguments different types, as mentioned above), and, for the life of me, I can't figure out where is the fault in my logic. 为了澄清我想要在该类中做什么,我想要在ProcessManager中调用executeProcess(String key,T parameters)时,要它在HashMap中搜索该键,然后执行该项目的(即ProcessExecute) executeProcess方法及其正确推断类型的方法(因为许多方法返回null或boolean或Strings或Integers并以不同的类型作为参数,如上所述),而且对于我来说,我不知道在哪里我的逻辑是错。

What confused me even further, is that I managed to find a (weird?) solution for this problem but I don't want to implement it since I simply don't understand why it works, so if you can please give me a hand on why the following works and how I can improve or change it, please do it. 更令我困惑的是,我设法找到了这个问题的(怪异?)解决方案,但是由于我根本不理解它为什么起作用,所以我不想实施它,所以如果可以的话,请帮我一下请说明以下原因,以及如何改进或更改它。 Basically, if I change the executeRam method to this: 基本上,如果我将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;
}

Then it will give no errors in the initializeMap() method (and it actually works). 然后,它将不会在initializeMap()方法中给出任何错误(并且它实际上可以工作)。 But it kinda seems weird and ungly to cast the return to K (?). 但是将返回值强制转换为K(?)似乎有点怪异和怪异。 Also, this solution of changing all the other methods is not complete : on my methods that have primitive return types such as boolean, it will complain that it can not cast boolean to K, so I can't adapt my solution to other methods. 此外,更改所有其他方法的解决方案也不完整:在我的具有原始返回类型(例如boolean)的方法上,它将抱怨无法将boolean强制转换为K,因此我无法将我的解决方案适应其他方法。

The problem you've got here is that you're declaring the type variables on the method. 您在这里遇到的问题是要在方法上声明类型变量。

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

means you can pass anything to the method, and expect to get back any type whatsoever. 意味着您可以将任何内容传递给该方法,并期望返回任何类型。

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

This will result in a ClassCastException when you invoke it, unless either you use the result as an Object (as in Object obj = pex.execute(""); ), or you return null from the method. 除非您将结果用作Object (如Object obj = pex.execute(""); ),或者从该方法返回null ,否则在调用它时将导致ClassCastException

Instead: 代替:

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

means that, given an instance of ProcessExecute , you always have to pass in the same parameter type, and you will always get back the same parameter. 意味着,在给定ProcessExecute实例的情况下,您始终必须传递相同的参数类型,并且始终将返回相同的参数。

You can then use an instance of this like so: 然后,您可以使用如下所示的实例:

ProcessExecute<Void, Process> ramMonitor = ProcessManager::executeRam;
Process p = ramMonitor.executeProcess(null);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM