514. Java 方法句柄 - 转换
到目前为止,我们看到 MethodHandle 不仅仅是对某个方法的直接引用。
它还可以通过 转换(transformations) 被“包装”成新的方法句柄,从而支持更灵活的操作。
常见的转换包括:
- 类型转换(Type Transformation)
- 参数重排(Permute Arguments)
这些转换的核心思想是:
原始 MethodHandle 始终存在,而转换得到的新句柄在外层“套了一层逻辑”,会在调用前后对参数和返回值做适配。
1. 类型转换 (asType) 🔄
有时我们需要调整 MethodHandle 的参数或返回值类型,使其与调用方的需求匹配。
这可以通过 asType 方法实现。
示例
假设我们有一个方法,接收 Object 参数并返回 String:
public static String test(Object obj) {
return "Value: " + obj.toString();
}
查找对应的 MethodHandle:
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle target = lookup.findStatic(
Example.class,
"test",
MethodType.methodType(String.class, Object.class));
现在我们想适配成 接收 String 参数的句柄:
MethodHandle adapter = target.asType(
MethodType.methodType(String.class, String.class));
测试调用:
String result1 = (String) target.invoke(111); // ✔ 输出 "Value: 111"
System.out.println(result1);
String result2 = (String) adapter.invoke("hello"); // ✔ 输出 "Value: hello"
System.out.println(result2);
String result3 = (String) adapter.invoke(111); // ❌ 抛 WrongMethodTypeException
System.out.println(result3);
👉 注意:
-
asType允许我们在调用时进行类型适配。 - 如果类型不能安全转换(如
Integer -> String),就会抛WrongMethodTypeException。 - 实际上,每次
invoke()内部都会隐式调用一次asType来尝试类型适配。
2. 参数重排 (permuteArguments) 🔀
有时我们需要改变方法的参数顺序,可以用 permuteArguments 来实现。
示例
定义一个方法,接收多个不同类型的参数:
public static void test(int v1, String v2, long v3, boolean v4) {
System.out.println(v1 + v2 + v3 + v4);
}
找到对应的 MethodHandle:
MethodHandle target = lookup.findStatic(
Example.class,
"test",
MethodType.methodType(void.class, int.class, String.class, long.class, boolean.class));
我们希望参数顺序改成:boolean, long, String, int。
使用 permuteArguments:
MethodHandle reversed = MethodHandles.permuteArguments(
target,
MethodType.methodType(void.class, boolean.class, long.class, String.class, int.class),
3, 2, 1, 0);
reversed.invoke(false, 1L, "str", 123);
// 输出: "123str1false"
参数说明
-
第一个参数:原始
MethodHandle。 -
第二个参数:新的
MethodType(即新的参数顺序)。 - 第三个参数起:索引数组,表示新顺序下的参数如何映射到原顺序。
👉 这里 3, 2, 1, 0 表示:
- 新的第 1 个参数(boolean)对应原来的第 4 个参数。
- 新的第 2 个参数(long)对应原来的第 3 个参数。
- 新的第 3 个参数(String)对应原来的第 2 个参数。
- 新的第 4 个参数(int)对应原来的第 1 个参数。
🎯 总结
-
asType:用来做 参数/返回值的类型适配。- 适用于更严格的调用契约,比如把
(Object)->String转成(String)->String。 - 如果类型不兼容会抛异常。
- 适用于更严格的调用契约,比如把
-
permuteArguments:用来 重新排列方法参数顺序。- 适用于方法签名和调用方需求不一致,但逻辑相同的情况。
📌 类比比喻:
-
asType像 接口转换器,把接口换成你想要的形状。 -
permuteArguments像 插拔电线,把参数插槽顺序重新排列。