methodhandle_概览Java 7 MethodHandle及其用法

methodhandle

由于Java的Reflection API,我们已经能够在运行时检查和更改程序执行。 特别是,我们可以在运行时观察接口/类/方法和字段,而无需在编译时知道它们的名称。

JDK 7为这种动态/运行时检查引入了一个新的参与者,即方法句柄(即抽象类java.dyn.MethodHandle的子类)。 方法句柄为我们提供了调用非公共方法的不受限制的功能,例如,可以由访问它的类在非公共方法上形成它。 与使用Reflection API相比,访问检查是在创建方法句柄时执行的,而不是每次调用该方法时都执行。

假设我们有一个需要允许对其私有方法之一进行受控访问的类。 下面的类定义了此方法并描述了两种访问方法(Reflection / MethodHandle)。

public class MethodAccessExampleWithArgs {
 private final int i;

 public MethodAccessExampleWithArgs(int i_) {
  i = i_;
 }

 private void bar(int j, String msg) {
  System.out.println("Private Method \'bar\' successfully accessed : "
    + i + ", " + j + " : " + msg + "!");
 }

 // Using Reflection
 public static Method makeMethod() {
  Method meth = null;

  try {
   Class[] argTypes = new Class[] { int.class, String.class };

   meth = MethodAccessExampleWithArgs.class.getDeclaredMethod("bar",
     argTypes);

   meth.setAccessible(true);
  } catch (IllegalArgumentException e) {
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   e.printStackTrace();
  } catch (SecurityException e) {
   e.printStackTrace();
  }

  return meth;
 }

 // Using method handles
 public static MethodHandle makeMh() {
  MethodHandle mh;

  MethodType desc = MethodType.methodType(void.class, int.class,
    String.class);

  try {
   mh = MethodHandles.lookup().findVirtual(
     MethodAccessExampleWithArgs.class, "bar", desc);
   System.out.println("mh=" + mh);
  } catch (NoAccessException e) {
   throw (AssertionError) new AssertionError().initCause(e);
  }
  return mh;
 }
}

以下是一个类,用于测试访问私有方法“ bar”的两种方法:

public class MethodAccessMain {

 private static void withReflectionArgs() {
  Method meth = MethodAccessExampleWithArgs.makeMethod();

  MethodAccessExampleWithArgs mh0 = new MethodAccessExampleWithArgs(0);
  MethodAccessExampleWithArgs mh1 = new MethodAccessExampleWithArgs(1);

  try {
   System.out.println("Invocation using Reflection");
   meth.invoke(mh0, 5, "Jabba the Hutt");
   meth.invoke(mh1, 7, "Boba Fett");
  } catch (IllegalAccessException e) {
   e.printStackTrace();
  } catch (IllegalArgumentException e) {
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   e.printStackTrace();
  }
 }

 private static void withMhArgs() {
  MethodHandle mh = MethodAccessExampleWithArgs.makeMh();

  MethodAccessExampleWithArgs mh0 = new MethodAccessExampleWithArgs(0);
  MethodAccessExampleWithArgs mh1 = new MethodAccessExampleWithArgs(1);

  try {
   System.out.println("Invocation using Method Handle");
   mh.invokeExact(mh0, 42, "R2D2");
   mh.invokeExact(mh1, 43, "C3PO");
  } catch (Throwable e) {
   e.printStackTrace();
  }
 }

 public static void main(String[] args) {
  withReflectionArgs();
  withMhArgs();
 }
}



如何运行代码– JDK7 b129和Netbeans 7.0 Beta 2

上面的代码已经在Netbeans IDE 7.0 Beta 2下使用JDK 7的内部版本129进行了测试,并且要运行,它需要以下额外的VMOptions: -XX:+ UnlockExperimentalVMOptions -XX:+ EnableMethodHandles -XX:+ EnableInvokeDynamic“运行”>下>设置项目配置>>自定义>> VMoptions ,以便在不接收运行时异常的情况下使用InvokeDynamic和MethodHandle。

JDK7 b131和Netbeans 7.0 Beta 2的问题

如果您已升级到最新版本131,则结果将取决于编译和运行代码的环境。 更具体地说,Netbeans IDE 7.0 Beta 2输出以下内容:

run:
Invocation using Reflection
Private Method 'bar' successfully accessed : 0, 5 : Jabba the Hutt!
Private Method 'bar' successfully accessed : 1, 7 : Boba Fett!

java.dyn.WrongMethodTypeException: (ILjava/lang/String;)V cannot be called as ([Ljava/lang/Object;)Ljava/lang/Object;
mh=bar(MethodAccessExampleWithArgs,int,String)void
Invocation using Method Handle
at ben.example.MethodAccessMain.withMhArgs(MethodAccessMain.java:46)
at ben.example.MethodAccessMain.main(MethodAccessMain.java:55)

BUILD SUCCESSFUL (total time: 0 seconds)

JDK7 b131和Eclipse 3.6.2的问题

该示例已在Eclipse 3.6.2 Helios上使用相同的参数-XX:+ UnlockExperimentalVMOptions -XX:+ EnableMethodHandles -XX:+ EnableInvokeDynamic“运行>>运行配置>>参数>> VM参数”下进行了进一步测试,但是我们已经提供相同的输出。

从已经提示我们的异常中,我们可以看到,我们的方法原本是用int(I),字符串(Ljava / lang / String)调用并返回void(V)来调用的,而不是使用Object的数组,并返回一个Object。 这表明在IDE中使用的编译器存在一些问题(可能与命令行编译器不同)。

在命令行上运行代码JDK7 b131

如果您碰巧在计算机上构建了129后JDK7,并且希望运行上述示例而没有任何问题,则可能应该坚持编译(javac)并运行( java -XX:+ UnlockExperimentalVMOptions -XX:+ EnableMethodHandles -XX:+ EnableInvokeDynamic com.wgjd.MethodHandleExample.MethodAccessMain )从命令行输入MethodHandle代码。

修复了JDK7 b131和IDE

目前尚无确定何时可以运行方法句柄而没有额外的VMOptions开销的日期,但是如果您想跟上达芬奇机器项目的最新动态,请注意动态调用的实现,确保您已订阅其邮件列表

还值得一提的是,从前面提到的邮件列表中,我们发现有一个复杂的更改,该更改将多包代码合并到一个包中,并包括准备从java.dynjava.lang的干净重命名。调用 。 修复由于多个包之间的依赖性而导致的API中的某些缺陷是必需的。

参考文献:

编码愉快! 不要忘记分享!

拜伦

相关文章:


翻译自: https://www.javacodegeeks.com/2011/03/glimpse-at-java-7-methodhandle-and-its.html

methodhandle

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值