Java编程的动态性,第8部分: 用代码生成取代反射

从本系列前面的文章中,您了解到反射的性能比直接访问要慢许多倍,并了解了用 Javassist 和 Apache Byte Code Engineering Library (BCEL)进行classworking。Java 顾问 Dennis Sosnoski 通过演示如何使用运行时 classworking,来用全速前进的生成代码 取代反射代码,从而结束他的 Java 编程的动态性系列。

既然您已经看到了如何使用 Javassist 和 BCEL 框架来进行 classworking ,我将展示 一个实际的 classworking 应用程序。这个应用程序用运行时生成的、并立即装载到 JVM 的 类来取代反射。在综合讨论的过程中,我将引用本系列的前两篇文章,以及对 Javassist 和 BCEL 的讨论,这样本文就成为了对这个很长的系列文章的一个很好的总结。

反射的性能

在 第 2 部分,我展示了无论是对于字段访问还是方法调用,反射都比直接代码慢很多倍 。这种延缓对于许多应用程序来说不算是问题,但是总是会遇到性能非常关键的情况。在这 种情况下,反射可能成为真正的瓶颈。但是,用静态编译的代码取代反射可能会非常混乱, 并且在有些情况下(如在这种框架中:反射访问的类或者项目是在运行时提供的,而不是作 为这一编译过程的一部分提供的),如果不重新构建整个应用程序就根本不可能取代。

Classworking 使我们有机会将静态编译的代码的性能与反射的灵活性结合起来。这里的 基本方法是,在运行时,以一种可以被一般性代码使用的方式,构建一个自定义的类,其中 将包装对目标类的访问(以前是通过反射达到的)。将这个自定义类装载到 JVM 中后,就可 以全速运行了。

设置阶段

清单 1 给出了应用程序的起点。这里定义了一个简单的 bean 类 HolderBean 和一个访 问类 ReflectAccess 。访问类有一个命令行参数,该参数必须是一个值为 int 的 bean 类 属性的名字( value1 或者 value2 )。它增加指定属性的值,然后在退出前打印出这两个 属性值。

清单 1. 反射一个 bean

public class HolderBean
{
   private int m_value1;
   private int m_value2;

   public int getValue1() {
     return m_value1;
   }
   public void setValue1(int value) {
     m_value1 = value;
   }

   public int getValue2() {
     return m_value2;
   }
   public void setValue2(int value) {
     m_value2 = value;
   }
}
public class ReflectAccess
{
   public void run(String[] args) throws Exception {
     if (args.length == 1 && args[0].length() > 0)  {

       // create property name 
       char lead = args[0].charAt(0);
       String pname = Character.toUpperCase(lead) +
         args[0].substring(1);

       // look up the get and set methods
       Method gmeth = HolderBean.class.getDeclaredMethod
         ("get" + pname, new Class[0]);
       Method smeth = HolderBean.class.getDeclaredMethod
         ("set" + pname, new Class[] { int.class });

       // increment value using reflection
       HolderBean bean = new HolderBean();
       Object start = gmeth.invoke(bean, null);
       int incr = ((Integer)start).intValue() + 1;
       smeth.invoke(bean, new Object[] {new Integer(incr)});

       // print the ending values
       System.out.println("Result values " +
         bean.getValue1() + ", " + bean.getValue2());

     } else {
       System.out.println("Usage: ReflectAccess value1|value2");
     }
   }
}

下面是运行 ReflectAccess 的两个例子,用来展示结果:

[dennis]$ java -cp . ReflectAccess value1
Result values 1, 0
[dennis]$ java -cp . ReflectAccess value2
Result values 0, 1

时间: 2024-10-04 12:00:51

Java编程的动态性,第8部分: 用代码生成取代反射的相关文章

Java编程的动态性,第5部分: 动态转换类

在经过一段时间的休息之后,Dennis Sosnoski 又回来推出了他的 Java 编程的动态性系 列的第 5 部分.您已在前面的文章中看到了如何编写用于转换 Java 类文件以改变代码行为 的程序.在本期中,Dennis将展示如何使用 Javassist 框架,把转换与实际的类加载过程结 合起来,用以进行灵活的"即时"面向方面的特性处理.这种方法允许您决定想要在运行时 改变的内容,并潜地在每次运行程序时做出不同的修改.在整个过程中,您还将更深入地了 解向JVM 中加载类的一般问题.

Java编程的动态性, 第4部分: 用Javassist进行类转换

厌倦了只能按编写好源代码的方式执行的 Java 类了吗?那么打起精神吧,因为您就要发 现如何将编译器编译好的类进行改造的方法了!在本文中,Java 顾问 Dennis Sosnoski 通 过介绍字节码操作库 Javassist 将他的 Java 编程的动态性系列带入高潮,Javassist 是广 泛使用的 JBoss 应用服务器中加入的面向方面的编程功能的基础.您会看到到用 Javassist 转换现有类的基本内容,并且了解到这种用框架源代码处理类的方法的威力和局限性. 讲过了 Java 类格

Java编程的动态性,第2部分: 引入反射

在" Java编程的动态性,第1部分,"我为您介绍了Java编程类和类装入.该篇文章介绍 了一些Java二进制类格式的相关信息.这个月我将阐述使用Java反射API来在运行时接入和使 用一些相同信息的基础.为了使已经熟知反射基础的开发人员关注本文,我将在文章中包括 反射性能如何与直接接入相比较. 使用反射不同于常规的Java编程,其中它与 元数据--描述其它数据的数据协作.Java语 言反射接入的特殊类型的原数据是JVM中类和对象的描述.反射使您能够运行时接入广泛的类 信息.它甚至使您

Java编程的动态性,第1部分: 类和类装入

本文是这个新系列文章的第一篇,该系列文章将讨论我称之为 Java 编程的动态性的一系 列主题.这些主题的范围从 Java 二进制类文件格式的基本结构,以及使用反射进行运行时 元数据访问,一直到在运行时修改和构造新类.贯穿整篇文章的公共线索是这样一种思想: 在 Java 平台上编程要比使用直接编译成本机代码的语言更具动态性.如果您理解了这些动 态方面,就可以使用 Java 编程完成那些在任何其它主流编程语言中不能完成的事情. 本文中,我将讨论一些基本概念,它们是这些 Java 平台动态特性的基础.

Java编程的动态性,第6部分: 利用Javassist进行面向方面的更改

Java 顾问 Dennis Sosnoski 在他的关于 Javassist 框架的三期文章中将精华部分留在 了最后.这次他展现了 Javassist 对搜索-替换的支持是如何使对 Java 字节码的编辑变得 像文本编辑器的"替换所有(Replace All )"命令一样容易的.想报告所有写入特定字段 的内容或者对方法调用中参数的更改中的补丁吗?Javassist 使这变得很容易,Dennis 向您 展示了其做法. 本系列的 第 4 部分和 第 5 部分讨论了如何用 Javassis

Java编程的动态性,第7部分: 用BCEL设计字节码

Apache Byte Code Engineering Library (BCEL)可以深入 Java 类的字节码.可以用它 转换现有的类表示或者构建新的类,因为 BCEL 在单独的 JVM 指令级别上进行操作,所以可 以让您对代码有最强大的控制.不过,这种能力的代价是复杂性.在本文中,Java 顾问 Dennis Sosnoski 介绍了 BCEL 的基本内容,并引导读者完成一个示例 BCEL 应用程序,这 样您就可以自己决定是否值得以这种复杂性来换取这种能力. 在本系列的最后三篇文章中,我

Java编程的动态性,第3部分: 应用反射

命令行参数处理是一项令人厌烦的零碎工作,不管您过去已经处理过多少次了,它好像总 能重新摆在您的面前.与其一遍又一遍地编写同一块代码的不同变种,为什么不利用反射来 简化参数处理的工作呢?Java 顾问 Dennis Sosnoski 向您展示了如何做到这一点.在本文 中,Dennis 简明扼要地介绍了一个开源库,这个库可以使得命令行参数实际上自己处理自己 . 在 上个月的文章中,我介绍了Java Reflection API,并简要地讲述了它的一些基本功能 .我还仔细研究了反射的性能,并且在文章的

java代码-关于CSDN英雄会挑战赛 java编程中的一些问题

问题描述 关于CSDN英雄会挑战赛 java编程中的一些问题 各位大神,我在挑战英雄会的题目的时候,在线下运行的没有问题,可是一提交就会提示,"挑战失败:你的程序正常编译,不过运行时发生错误,通常是代码有问题,如除数为零数组上下界溢出等" 我觉得可能是java输入数据时的问题,因为题目要求:输入多行数据,输出多行我是这样写的: Scanner scanner = new Scanner(System.in); ArrayList list = new ArrayList(); do {

java编程,在屏幕上显示一个带标题的窗口,并添加一个按钮

问题描述 java编程,在屏幕上显示一个带标题的窗口,并添加一个按钮 编写程序,在屏幕上显示一个带标题的窗口,并添加一个按钮,当用户单击按钮时,弹出对话框,显示用户单击了按钮. 解决方案 找点Java 的 Swing学习资料,这种界面估计用netbean或idea都可以自动生成. 解决方案二: import java.awt.Frame; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.event.Act