![](/img/trans.png)
[英]How to Invoke a method that take a Callable Interface or method as parameter with java reflection
[英]Is there a way to take an argument in a callable method?
我創建了一段代碼,它獲取一個 IP 地址(來自另一個類中的 main 方法),然后循環遍歷一系列 IP 地址,並在執行過程中對每個地址進行 ping 操作。 我有一個 GUI 前端,它崩潰了(因此我做了多線程處理。我的問題是我不能再將 IP 地址作為我的 ping 代碼中的參數作為它的可調用參數。我已經搜索過了為此,似乎無法找到解決此問題的方法。有沒有辦法讓可調用方法接受參數?如果沒有,還有其他方法可以完成我想要做的事情嗎?
我的代碼示例:
public class doPing implements Callable<String>{
public String call() throws Exception{
String pingOutput = null;
//gets IP address and places into new IP object
InetAddress IPAddress = InetAddress.getByName(IPtoPing);
//finds if IP is reachable or not. a timeout timer of 3000 milliseconds is set.
//Results can vary depending on permissions so cmd method of doing this has also been added as backup
boolean reachable = IPAddress.isReachable(1400);
if (reachable){
pingOutput = IPtoPing + " is reachable.\n";
}else{
//runs ping command once on the IP address in CMD
Process ping = Runtime.getRuntime().exec("ping " + IPtoPing + " -n 1 -w 300");
//reads input from command line
BufferedReader in = new BufferedReader(new InputStreamReader(ping.getInputStream()));
String line;
int lineCount = 0;
while ((line = in.readLine()) != null) {
//increase line count to find part of command prompt output that we want
lineCount++;
//when line count is 3 print result
if (lineCount == 3){
pingOutput = "Ping to " + IPtoPing + ": " + line + "\n";
}
}
}
return pingOutput;
}
}
IPtoPing 曾經是采用的參數。
您不能將它作為參數傳遞給call()
因為方法簽名不允許它。
但是,您可以將必要的信息作為構造函數參數傳遞; 例如
public class DoPing implements Callable<String>{
private final String ipToPing;
public DoPing(String ipToPing) {
this.ipToPing = ipToPing;
}
public String call() throws SomeException {
InetAddress ipAddress = InetAddress.getByName(ipToPing);
....
}
}
(我已經糾正了一些嚴重的代碼風格違規行為!!)
有一些方法可以消除上面的一些“樣板”編碼(請參閱其他一些答案)。 在這種情況下,我們談論的是 4 行代碼(在大約 40 行的類中),所以我不相信這是值得的。 (但是,嘿,這是您的代碼。)
或者,您可以:
將 DoPing 聲明為內部類(或 lambda)並讓它引用封閉范圍內的final ipToPing
,或
添加一個setIpToPing(String ipToPing)
方法。
(最后一個允許重復使用DoPing
對象,但缺點是您需要同步以線程安全地訪問它。)
添加到 Jarle 的答案 - 如果您將Callable
創建為匿名類的實例,則可以使用匿名類之外的final
字段將數據傳遞到實例中:
final int arg = 64;
executor.submit(new Callable<Integer>() {
public Integer call() throws Exception {
return arg * 2;
}
});
您不能將參數傳遞給call()
因為方法簽名不允許它但這里至少有一種方法可以解決這個問題
Callable
和call()
定義一個抽象類:
import java.util.concurrent.Callable;
public abstract class Callback<T> implements Callable<Void> {
T result;
void setResult (T result) {
this.result = result;
}
public abstract Void call ();
}
定義應該觸發回調的方法:
public void iWillFireTheCallback (Callback callback) {
// You could also specify the signature like so:
// Callback<Type of result> callback
// make some information ("the result")
// available to the callback function:
callback.setResult("Some result");
// fire the callback:
callback.call();
}
在您要調用iWillFireTheCallback
的地方:
定義回調函數(甚至可能在方法內部):
class MyCallback extends Callback {
@Override
public Void call () {
// this is the actual callback function
// the result variable is available right away:
Log.d("Callback", "The result is: " + result);
return null;
}
}
然后在傳入回調時調用iWillFireTheCallback
:
iWillFireTheCallback(new MyCallback());
創建 doPing 類時(類名中應該是大寫字母),在構造函數中發送 ip-address。 在 call-method 中使用這個 ip-address。
在doPing
類中放置一些( final
)字段,以及初始化它們的構造函數,然后將要在call()
使用的值傳遞給doPing
的構造doPing
:
public class DoPing implements Callable<String> {
private final String ipToPing;
public DoPing(String ip) {
this.ipToPing = ip;
}
public String call() {
// use ipToPing
}
}
你必須defien屬性,如ipAddress
和其存取方法。 並在constructor
或setter
方法中傳遞其值。 在doPing
類使用ipAddress
屬性。
class DoPing/* In java all classes start with capital letter */implements Callable<String>
{
private String ipAddress;
public String getIpAddress()
{
return ipAddress;
}
public void setIpAddress(String ipAddress)
{
this.ipAddress = ipAddress;
}
/*
* Counstructor
*/
public DoPing(String ipAddress )
{
this.ipAddress = ipAddress;
}
@Override
public String call() throws Exception
{
// your logic
}
}
並非總是可以引用(有效)最終變量以將其值用作“參數”,但您可以自己制定舒適的通用解決方案。 首先定義這個功能接口:
@FunctionalInteface
interface CallableFunction<T, R> {
public abstract R call(T arg) throws Exception;
public static <T, R> Callable<R> callable(CallableFunction<T, R> cf, T arg) {
return () -> cf.call(arg);
}
}
這個函數式接口提供了靜態方法callable
,它創建了一個Callable
實例,它簡單地使用提供的參數(T 類型)調用call(T)
T)。 然后你需要你的DoPing
類來實現CallableFunction
像這樣:
public class DoPing implements CallableFunction<String, String> {
@Override
public String call(final String ipToPing) throws Exception {
final var ipAddress = InetAddress.getByName(ipToPing);
final var reachable = ipAddress.isReachable(1400);
String pingOutput = null;
if (reachable) {
pingOutput = ipToPing + " is reachable.\n";
}
else {
final var ping = Runtime.getRuntime().exec("ping " + ipToPing + " -n 1 -w 300");
try (var in = new BufferedReader(new InputStreamReader(ping.getInputStream()))) {
String line;
for (int lineCount = 1; (line = in.readLine()) != null; ++lineCount) {
if (lineCount == 3) {
pingOutput = "Ping to " + ipToPing + ": " + line + "\n";
break;
}
}
}
}
return pingOutput;
}
在這里,我們將call
簽名更改為接受String
參數,並且現在它實現了CallableFunction
而不是像以前那樣Callable
。 其他更改很小,但值得一提的是,我們通過在BufferedReader
上使用 try-with-resource 來防止資源泄漏,並且還向輸入收集循環添加了break
(從while
更改為for
)以盡可能快地終止。
現在你可以像這樣使用代碼:
final var ping = CallableFunction.callable(new DoPing(), "127.0.0.1");
final var task = new FutureTask<>(ping);
new Thread(task).start();
System.out.println(task.get(20, TimeUnit.SECONDS));
您還可以在需要時在其他情況下重用CallableFunction
。
我知道現在回答這個問題太晚了,考慮到它已經有 8 年歷史了,但在 15 天(!)前活躍,我覺得這仍然會對使用 Java 8 及更高版本的人有所幫助。
PS,這只是 Victor Sorokin 可能通過 lambdas 回答的語法糖。
public static Callable<String> generateCallableWithArg(final String input) {
return () -> {
Thread.sleep(5000); // someExpensiveOperationHere
return "Return Value of " + input; //input can be used here
};
}
此外,我們可以編寫一個靜態輔助方法,可以將 Function 轉換為 Callable。
public class CallableGenerator {
public static <T,V> Callable<V> getCallableFromFunction(Function<T, V> function, T input) {
return () -> function.apply(input);
}
}
這可以用作
Callable<Integer> iAmCallable = CallableGenerator.getCallableFromFunction(i1 -> i1 * 2, 3);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.