[英]Want to pass class.getmethod arguments dynamically in run time java
我想通過在運行時提供methodName來調用方法。 我可以按照以下方式來做。
Method method = MyObject.class.getMethod("doSomething", String.class);
Object returnValue = method.invoke(null, "parameter-value1");
但是我想列出所有帶有該方法名稱和不同參數集的重載方法,並讓用戶選擇一個特定的重載方法並在其中動態傳遞這些參數。
Method method = MyObject.class.getMethod("doSomething", String.class);
而不是對String.class
進行硬編碼。
假設我有兩種方法
methodName(String)
和重載方法
methodName(String, int)
我想讓用戶選擇在運行時中選擇哪個,並將該信息傳遞給該特定方法的getMethod
函數。
我怎樣才能做到這一點?
我們有一個稱為Class.forName(String)
的方法,用於通過其名稱加載Class<?>
的實例。
問題是我們必須傳遞所需類的全限定名(包括包名)。 這意味着Class.forName("String")
將無法正常工作。 相反,我們需要將其稱為Class.forName("java.lang.String")
。
我們可以有一個映射(或枚舉)來保留這些Class<?>
es。 由於我們期望用戶進行協作,因此鍵將為String
,結構將類似於Map<String, Class<?>>
:
user > string
we < class java.util.String
然后,我們應該弄清楚如何根據它們的類型解析方法參數-它們將作為String
。 我會使用每個類型的Function<String, ?>
:
Function<String, T> converter = (String s) -> T.convertFromString(s);
為了使您更清楚,我為您編寫了一個簡單而完整的示例:
class Test {
// prints s once
public static void method(String s) {
System.out.println(s);
}
// prints s i times
public static void method(String s, int i) {
System.out.println(IntStream.rangeClosed(0, i - 1)
.mapToObj($ -> s)
.collect(Collectors.joining(" ")));
}
public static void main(String[] args) {
perform();
}
public static Object perform() {
final Scanner scanner = new Scanner(System.in);
// read the method name
final String methodName = scanner.nextLine();
final Method[] methods = Arrays.stream(Test.class.getDeclaredMethods())
.filter(m -> m.getName().endsWith(methodName) && !m.isSynthetic())
.toArray(Method[]::new);
// read the method parameter types in the format "type1 type2"
final String rawMethodParametersTypes = scanner.nextLine();
final SupportedType[] methodParameterTypes = Arrays.stream(rawMethodParametersTypes.split(" "))
.map(p -> SupportedType.valueOf(p.toUpperCase()))
.toArray(SupportedType[]::new);
final Optional<Method> selectedMethod = Arrays.stream(methods)
.filter(m -> Arrays.equals(Arrays.stream(methodParameterTypes)
.map(SupportedType::getType).toArray(Class<?>[]::new), m.getParameterTypes()))
.findAny();
if (!selectedMethod.isPresent()) {
return null;
}
final Method method = selectedMethod.get();
// read method arguments in the format "arg1 arg2"
final String rawMethodArgumentsLine = scanner.nextLine();
final String[] rawMethodArguments = rawMethodArgumentsLine.split(" ");
final int expectedLength = method.getParameterCount();
if (rawMethodArguments.length != expectedLength) {
return null;
}
Object[] methodArguments = new Object[expectedLength];
for (int i = 0; i < expectedLength; ++i) {
methodArguments[i] = methodParameterTypes[i].getConverter().apply(rawMethodArguments[i]);
}
try {
return method.invoke(null, methodArguments);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
我引入了一個枚舉SupportedType
來聲明我們將要支持的類型以及用戶在選擇簽名時可能遇到的類型。
@RequiredArgsConstructor
public enum SupportedType {
STRING(String.class, s -> s),
INT(int.class, Integer::valueOf);
@Getter
private final Class<?> type;
@Getter
private final Function<String, Object> converter;
}
這是method(String, int)
輸入輸出示例
> method
> string int
> hello 5
< hello hello hello hello hello
和method(String)
> method
> string
> hello
< hello
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.