我有以下代码,test case 中的 value 可能是 String 类型,也有可能是 Integer 类型等等。如何根据参数类型调用不同的方法呢?我不想使用 if else 。
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
// test cases
Object[][] testCases = new Object[][]{
{"name", "Martin", "Martin"},
{"age", 23, "23"}
};
for (Object[] testCase : testCases) {
String k = (String) testCase[0];
// extract v
String expectedResult = (String) testCase[2];
// How can I invoke the correct method without using if else?
// For value "Martin", I want to invoke putStr, for value 23, I want to invoke putInt
}
}
}
class DataContainer {
private final Map<String, String> map = new HashMap<>();
public void putStr(String k, String v) {
map.put(k, v);
}
public void putInt(String k, Integer v) {
map.put(k, String.valueOf(v));
}
public String get(String k) {
return map.get(k);
}
}
1
JasonLaw OP Sorry ,putStr(String k, String v)应该为 put(String k, String v),putInt(String k, Integer v)应该为 put(String k, Integer v),我知道通过反射能够解决这个问题。除了反射之外呢?有没有其它优雅一点的方法?
|
2
Alphones 2023-07-13 00:06:42 +08:00
方法名字没必要区分 putStr 或者 putInt ,都叫 put
public void put(String k, String v) { map.put(k, v); } public void put(String k, Integer v) { this.put(k,String.valueOf(v)); } |
3
Alphones 2023-07-13 00:13:35 +08:00
@Alphones 忘了补充上面反射的用法,具体参考如下
Method put = DataContainer.class.getMethod("put", testCase[0].getClass(), testCase[1].getClass()); put.invoke(container,k,v); |
5
xuanbg 2023-07-13 08:07:18 +08:00
相同方法名称,不同方法参数,这叫重载。。。。。代码会根据不同的参数类型自动调用合适的方法。
|
6
JasonLaw OP @xuanbg #5 你可以先详细阅读一下题目,value 的类型是 Object ,你可能会问为什么是 Object ,因为我使用了 TestNG 的 DataProvider 。
|
7
Alphones 2023-07-13 09:22:06 +08:00
@JasonLaw 不想走反射的话,如果业务量就是那么少,if else 是没问题的,如果后续可能要拓展成多种情况,可以考虑定义一个抽象类和相关的一个入口方法以及钩子方法,以及针对不同类型定义相关的策略对象类,这些策略类可以直接继承上面提到的抽象类并实现钩子方法,然后在抽象类的入口方法里面做一个判断处理最终调用
|
8
superychen 2023-07-13 09:24:37 +08:00
按照你这个代码,为啥还要区分 String 和 Integer ?直接一个 put(String k, Object v),里面 map.put(k, String.valueOf(v))不可以吗,如果 v 是 String ,调用一次 String.valueOf(v)也没啥问题
|
9
superychen 2023-07-13 09:27:14 +08:00
```java
class DataContainer { private final Map<String, String> map = new HashMap<>(); public void put(String key, Object v) { map.put(key, null == v ? null : String.valueOf(v)); } public String get(String k) { return map.get(k); } } ``` |
10
JasonLaw OP @superychen #8 因为不单单是 String 和 Integer ,还有可能是 Instant 等类型。
|
11
dragondove 2023-07-13 09:49:41 +08:00
String val = switch(o) {
case Integer i -> String.valueOf(i); case String s -> s; } |
12
superychen 2023-07-13 10:16:40 +08:00
@JasonLaw 那感觉只能为每个 class 类型指定 toString 方法,最后根据 class 类型直接找对应方法进行转换
private static final Map<Class<?>, Function<Object, String>> FUNCTIONS = Map.of( String.class, String::valueOf, Integer.class, String::valueOf, Instant.class, Object::toString ); public void put(String key, Object v) { map.put(key, null == v ? null : FUNCTIONS.get(v.getClass()).apply(v)); } |
13
JasonLaw OP @superychen #12 不过我不能加一个 put(String key, Object v)。anyway, thank you.
|
14
wangYQ 2023-07-13 11:15:19 +08:00
可以用个策略模式,用标识不同类型实现不同的策略就可以
|
15
zhady009 2023-07-13 12:37:12 +08:00
感觉你是需要一个 Jackson 根据 Key+期望的类型对 value 进行转换
|
16
sl450282169 2023-07-13 13:39:24 +08:00
升级到 jdk17 使用模式匹配即可
public void process(Object obj) { if (obj instanceof String s) { System.out.println("String value: " + s); } else if (obj instanceof Integer i) { System.out.println("Integer value: " + i); } else if (obj instanceof Boolean b) { System.out.println("Boolean value: " + b); } else { System.out.println("Unexpected type"); } } |
17
sl450282169 2023-07-13 13:44:53 +08:00
还有预览版的 switch
public void process(Object obj) { switch (obj) { case String s -> System.out.println("String value: " + s); case Integer i -> System.out.println("Integer value: " + i); case Boolean b -> System.out.println("Boolean value: " + b); default -> System.out.println("Unexpected type"); } } |
18
montaro2017 2023-07-13 16:08:06 +08:00
通过参数类型去查找方法,但是可能找到的不是正确的方法,下面 DataContainer 中的方法最好用重载写
```java public class MatchMethod { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { // test cases Object[][] testCases = new Object[][]{ {"name", "Martin", "Martin"}, {"age", 23, "23"}, {"age", "23"} }; DataContainer instance = new DataContainer(); Method[] methods = DataContainer.class.getMethods(); for (Object[] testCase : testCases) { Class<?>[] methodParameterTypes = Arrays.stream(testCase).map(Object::getClass).toArray(Class[]::new); Method method = findMethod(methods, methodParameterTypes); if (method != null) { System.out.println("method = " + method.toGenericString()); method.invoke(instance, testCase); } else { System.out.println("method is null"); } } } private static Method findMethod(Method[] methods, Class<?>[] methodParameterTypes) { for (Method method : methods) { Class<?>[] parameterTypes = method.getParameterTypes(); if (Arrays.equals(parameterTypes, methodParameterTypes)) { return method; } } return null; } } ``` 输出 ``` method is null method is null method = public void DataContainer.putStr(java.lang.String,java.lang.String) ``` |
19
wolfie 2023-07-13 17:08:36 +08:00
putStr 、putInt 参数列表 类型不同,不然可以用 FunctionalInterface 。
--- 你这个最好弄成,ValueDecorator 。 |