如何使用 Java 反射调用接受 Callable 接口或方法作为参数的方法。

huangapple go评论70阅读模式
英文:

How to Invoke a method that take a Callable Interface or method as parameter with java reflection

问题

假设我有一个接受 Callable 接口作为参数的方法。

使用 Java 反射,我想调用一个接受 method 作为参数的方法。

我遇到了异常:Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch

以下展示了我的代码。

有人知道如何实现我的意图吗?

感谢您的回答!

package com.helloworld;

import android.annotation.TargetApi;
import android.os.Build;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class FinallyBlock {
    public static void main(String[] args) throws Exception {
        Method[] methods = FinallyBlock.class.getDeclaredMethods();
        Method templateMethod = FinallyBlock.class.getDeclaredMethod("template", Callable.class);
        for (Method method : methods) {
            if (method.getName().equals("main") || method.getName().equals("template")) {
                continue;
            }
            System.out.println(templateMethod.invoke(null, method));
        }
    }

    @TargetApi(Build.VERSION_CODES.O)
    private static <T> T template(Callable<T> callable) throws Exception {
        System.out.println("-----begin-----");
        System.out.println(callable.call());
        System.out.println("*****end*****");

        return null;
    }

    private static int tryThrowFinallyReturn() {
        try {
            throw new RuntimeException();
        } finally {
            return 3;
        }
    }

    private static int tryReturnFinallyReturn() {
        try {
            return 1;
        } finally {
            return 3;
        }
    }

    private static int tryCatchFinallyAllReturn() {
        try {
            return 1;
        } catch (Exception e) {
            return 2;
        } finally {
            return 3;
        }
    }

    private static int gotoFinallyIfMeetReturnInTry() {
        try {
            System.out.println("try_before_return");
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            return 3;
        }
    }

    private static int gotoFinallyIfMeetReturnInCatch() {
        try {
            throw new Exception();
        } catch (Exception e) {
            System.out.println("catch_before_return");
            return 2;
        } finally {
            return 3;
        }
    }

    private static int tryReturnFinallyNot() {
        try {
            return 1;
        } finally {
            System.out.println("finally block");
        }
    }
}
英文:

Assume that I hava a Method that take Callable interface as parameters.

With java reflection.I want to invoke a method that take a method as parameter.

I got an Exception:Exception in thread &quot;main&quot; java.lang.IllegalArgumentException: argument type mismatch

Below shows my code.

Any one knows how to archive my intent?

Appreciate for you answer!

package com.helloworld;
import android.annotation.TargetApi;
import android.os.Build;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
/**
* @author linjiejun 
*/
public class FinallyBlock {
public static void main(String[] args) throws Exception {
//        template(FinallyBlock::tryThrowFinallyReturn);
//        template(FinallyBlock::tryReturnFinallyReturn);
//        template(FinallyBlock::tryCatchFinallyAllReturn);
//        template(FinallyBlock::gotoFinallyIfMeetReturnInTry);
//        template(FinallyBlock::gotoFinallyIfMeetReturnInCatch);
Method[] methods = FinallyBlock.class.getDeclaredMethods();
Method templateMethod = FinallyBlock.class.getDeclaredMethod(&quot;template&quot;, Callable.class);
for (Method method : methods) {
if (method.getName().equals(&quot;main&quot;) || method.getName().equals(&quot;template&quot;)) {
continue;
}
System.out.println(templateMethod.invoke(null,method));
}
}
@TargetApi(Build.VERSION_CODES.O)
private static &lt;T&gt; T template(Callable&lt;T&gt; callable) throws Exception {
System.out.println(&quot;-----begin-----&quot;);
System.out.println(callable.call());
System.out.println(&quot;*****end*****&quot;);
return null;
}
//    private static int tryThrowEx() {
//
//    }
//region finally 中有return 语句,try,catch block中的return,以及抛出异常都将失效。
//
// try 中抛出的异常,对catch依旧有效。
private static int tryThrowFinallyReturn() {
try {
throw new RuntimeException();
} finally {
return 3;
}
}
private static int tryReturnFinallyReturn() {
try {
return 1;
} finally {
return 3;
}
}
private static int tryCatchFinallyAllReturn() {
try {
return 1;
} catch (Exception e) {
return 2;
} finally {
return 3;
}
}
//endregion
/**
* try 中没有遇到return语句的内容会执行
* try 中遇到return语句,
* 就将控制权转移给
* finally block
*
* @return
*/
private static int gotoFinallyIfMeetReturnInTry() {
try {
System.out.println(&quot;try_before_return&quot;);
return 1;
} catch (Exception e) {
e.printStackTrace();
} finally {
return 3;
}
}
/**
* catch block 同 try block
* catch block 中没有遇到return语句的内容会执行
* 遇到return语句
* 就将控制权转移给
* finally block
*
* @return
*/
private static int gotoFinallyIfMeetReturnInCatch() {
try {
throw new Exception();
} catch (Exception e) {
System.out.println(&quot;catch_before_return&quot;);
return 2;
} finally {
return 3;
}
}
private static int tryReturnFinallyNot() {
try {
return 1;
} finally {
System.out.println(&quot;finally block&quot;);
}
}
}

答案1

得分: 1

你的 template() 方法接受一个 Callable&lt;T&gt;,但你传递了一个 Method,它没有实现 Callable&lt;T&gt;,所以出现了错误。你需要实现 Callable 接口。

所以,作为建议,你可以像这样做:

1- 创建一个 Callable 类(如果你想的话,可以使用匿名类)

public class MyCallableMethod implements Callable&lt;Integer&gt; {
    
    private Method m;
    
    public MyCallableMethod(Method m){
       this.m=m;
    }
    @Override
    public Integer call() throws Exception {
        return this.m.invoke(null);
    }
}

2- 将

System.out.println(templateMethod.invoke(null, method));

改为

System.out.println(templateMethod.invoke(null, new MyCallableMethod(method)));

当然,这只是与 "理论" 代码一起工作的示例,因为我无法编写、编译或调试代码。

另一种解决方法可能是将 template() 的签名从

private static &lt;T&gt; T template(Callable&lt;T&gt; callable)

改为

private static &lt;T&gt; T template(Method callable) 

然后相应地更改方法体,但我相信你需要 callable 来执行某种类型的并发任务。

英文:

Your template() method accepts a Callable&lt;T&gt;, instead you pass it a Method which does not implement Callable&lt;T&gt;, thats why the error. You need to implement the Callable Interface.

So, just as suggestion you could do something like this

1- create a Callable Class (you can do an anonomus class if you want)

public class MyCallableMethod implements Callable&lt;Integer&gt; {
private Method m;
public MyCallableMethod(Method m){
this.m=m;
}
@Override
public Integer call() throws Exception {
return this.m.invoke(null);
}
}

2 change

System.out.println(templateMethod.invoke(null,method));

whith

System.out.println(templateMethod.invoke(null,new MyCallableMethod(method)));

Of course this is just a trace of work with "theoric" code, as i cant neither write, neither compile nor debug the code.

Another solution could be change the signature of template() from

 private static &lt;T&gt; T template(Callable&lt;T&gt; callable)

to

private static &lt;T&gt; T template(Method callable) 

and change the method body accordingly, but i believe you need callable for some type of concurrent task

huangapple
  • 本文由 发表于 2020年10月24日 17:14:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/64511796.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定