知识大全 Java中利用Reflection API优化代码

Posted

篇首语:业精于勤而荒于嬉,行成于思而毁于随本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java中利用Reflection API优化代码相关的知识,希望对你有一定的参考价值。

Java中利用Reflection API优化代码  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  摘要  开发者通过各种各样的方法来尝试避免单调冗余的编程 一些编程的规则例如继承 多态或者设计模型可以帮助开发者避免产生多余的代码 不过由于软件开发方面存在着不确定性 因此这些规则并不能消除代码维护和重新编写的需要 在很多时候维护都是不可避免的 只有不能运作的软件才是从不需要维护的 不过 这篇文章介绍了你可以使用Java的Reflection API的功能来减少单调的代码编写 并可以使用活动的代码产生来克服reflection的限制   数据配置(由外部的源头得到数据并且将它装载到一个Java对象中)可以利用reflection的好处来创建一个可重用的方案 问题是很简单的 将数据由一个文件装入到一个对象的字段中 现在假设用作数据的目标Java类每星期改变一次?有一个很直接的解决方法 不过你必须不断地维护载入的过程来反映任何的改变 在更复杂的环境下 同样的问题可能会令系统崩溃掉 对于一个处理过运用XML的大型系统的人来说 他就会遇到过这个问题 要编写一个载入的过程通常是非常单调乏味的 由于数据源或者目标Java类的改变 你需要经常更新和重新编写代码 在这里我要介绍另一个解决方案 那就是使用映射 它通常使用更少的编码 并且可以在目标Java类发生改变后更新自己   最初 我想介绍一个使用Reflection在运行期间配置数据的方案 在开始的时候 一个动态 基于映射的程序要比一个简单的方法更有吸引力多了 随后 我要揭示出运行时Reflection的复杂性和冒险性 这篇文章将介绍由运行时的Reflection到活动的代码产生   由简单到复杂  我的第一个方案使用一个载入类将数据从一个文件载入到对象中 我的源代码含有对StringTokenizer对象下一节点方法的多次调用 在修改多次后 我的编码逻辑变得非常的直接 系统化 该类构造了专用的代码 在这个初始方案中 我只需要使用 个基本的对象    Strings    Objects    Arrays of objects  你可以影射类的对象来产生代码块 如下表所示   被影射来产生代码块的对象     我已经使用这个方案作了几次编码 因此我在写代码之前我已经知道该方案和代码的结构 难点在于该类是变化的 类的名字 成份和结构在任何时候都可能发生变化 而任何的改变你都要重新编写代码 虽然会发生这些变化 但是结构和下载的流程仍然是一样的 在写代码前 我仍然知道代码的结构和成份 我需要一个方法 来将头脑中的编码流程转换为一个可重用的 自动的形式 由于我是一个有效率的编程者 我很快就厌倦了编写几乎一样的代码 这时我想到了映射   数据配置通常需要一个源到目的数据的影射 影射可以是一个图解 DTD(document type definition 文档类型定义) 文件格式等 在这个例子中 映射将一个对象的类定义解释为我们要映射的流程 映射可以在运行时复制代码的功能 在需要重写代码时 我将载入的过程用映射来代替 它所需要的时间和重写是一样的   载入的工程可以概括为以下几步    解释 一个影射决定你在构造一个对象时需要些什么   请求数据 要满足构造的需要 要进行一个调用来得到数据   拖 数据由源中得到    推 数据被填充入一个对象的新实例   如果必要的话 重复步骤   你需要以下的类来满足以上的步骤   .数据类(Data classes) 由ASCII文件中的数据实例化 类定义提供数据的影射 数据类必须满足以下的条件    它们必须包含有一个构造器来接收全部必需的参数 以使用一个有效的状态来构造对象    它们必须由对象构成 这些对象是reflective过程知道如何处理的  .对象装载器(Object loader) 使用reflection和数据类作为一个影射来载入数据 产生数据请求   .载入管理器(Load manager) 作为对象装载器和数据源的中介层 将对数据的请求转换为一个数据指定的调用 这可以令对象载入器做到与数据源无关 通过它的接口和一个可载入的类对象通信   .数据循环接口(Data iterator interface) 载入管理器和载入类对象使用这个接口来由数据源中得到数据   一旦你创建了支持的类 你就可以使用以下的声明来创建和影射一个对象   FooFileIterator iter = new FooFileIterator(fileLocation log);  LoadManager manager = new FooFileLoadManager(iter);  SubFooObject obj =   (SubFooObject)ReflectiveObjectLoader initializeInstance(SubFooObject class manager log);   通过这个处理 你就创建了一个包含有文件内容的SubFooObject实例   局限  开发者必须决定使用哪个方案来解决问题是最好的 通常做出这个决定是最困难的部分 在考虑使用reflection作数据配置时 你要考虑到以下一些限制    不要令一个简单的问题复杂化 reflection是比较复杂的 因此在必要的时候才使用它 一旦开发者明白了reflection的能力 他就想使用它来解决所有的问题 如果你有更快 更简单的方案来解决问题时 你就不应该使用reflection(即使这个更好的方案可能使用更多的代码) reflection是强大的 但也有一些风险    考虑性能 reflection对性能的影响比较大 因为要在运行时发现和管理类属性需要时间和内存   重新评估方案  如上所述 使用运行时reflection的第一个限制是 不要令简单的问题复杂化 在使用reflection时 这是不可避免的 将reflection和递归结合起来是一个令人头痛的问题 重新看代码也是一件可怕的事情 而准确决定代码的功能也是非常复杂的 要知道代码的准确作用的唯一方法是使用一些取样数据 逐行地看 就象运行时一样 不过 对于每个可能的数据组合都使用这种方式几乎是不可能的 在这种情况下 使用单元测试代码可能有些帮助 不过也很可能出现错误 幸运的是 还有一个可选的方法   可选的方法  由上面列出的限制可以看到 在某些情况下 使用reflective载入过程可能是得不偿失的 代码产生提供了一个通用的选择方法 你也可以使用reflection来检查一个类并且为载入过程产生代码   Andrew Hunt和David Thomas介绍了两类的代码产生器 见The Pragmatic Programmer( /jwl#resources)   Passive(被动) 被动的代码产生器在实现代码时需要人工的干预 许多的IDE(集成开发环境)都提供相应的向导来实现    Active(主动) 主动的代码产生指的是代码一旦创建 就不再需要修改了 如果有问题产生 这个问题也应该在代码产生器中解决 而不是在产生的源文件中解决 在理想的情况下 这个过程应该包含在编译的处理过程中 从而确保类不会过期   代码产生的优点和缺点包含有以下方面   优点   .简单 产生的代码通常是更便于开发者阅读和调试   .编译过程的错误 Reflexive在运行时出现错误的机会要比编译的期间多 例如 改变被载入的对象将有可能令产生的载入类抛出一个编译的错误 不过reflexive过程将不会看到任何的区别 直到在运行时遇到这个类   缺点   .维护 使用被动的代码产生 修改被载入的对象将需要更新或者重新产生载入的类 如果该类被重新产生 那么自定义的东西就会丢失   回头再来看看主动代码产生的好处  在这里我们可以看到在运行时使用reflection是不可以接受的 主动的代码产生有着reflection的全部好处 但是没有它的限制 还可以继续使用reflection 不过只是在代码的产生过程 而不是运行的过程 理由如下    更少冒险 运行时的reflection明显是更冒险的 特别是问题变得复杂的时候    基于单元测试 但并不是编译器   多功能性 产生的代码有着runtime reflection的全部好处 而且有着runtime reflection没有的好处    更易懂 虽然经过多次的处理 但是将递归和reflection结合仍然是很复杂的 产生源代码的方式更加容易解释和理解 代码产生过程需要递归和reflection 但得到的结果是可查看的源代码 而不是难以理解的东西   写代码产生器  要写一个代码产生器 在思考的时候 你不能只是简单地编写一个方案来解决一个问题 你应该看得更远 代码产生器(以及reflection)需要你作更多的思考 如果你只是使用runtime reflection 你就不得不在运行时概念化问题 而不是使用简单 兼容性好的源代码来解决问题 代码产生要求你从两个方面来查看问题 代码产生过程会将抽象的概念转变为实际的源代码 Runtime reflection则一直是抽象的   代码产生过程将你的思考过程转变为代码 然后产生并且编译代码 编译器会让你知道你的思考过程在语法上是否正确 单元测试则可以验证代码在运行时的行为 就动态特性方面 runtime reflection就不能达到这个级别的安全性   代码产生器  在经历后几次失败的设计后 我认为最简单的方法是 在载入过程中 为每一种需要实例化的类产生一个方法 一个方法工厂产生每个特别类的正确方法 一个代码编译对象缓冲来自代码工厂的方法请求 以产生最终源代码文件的内容   MethodCode对象是代码产生过程的核心 以下就是一个int的代码产生对象的例子   public class MethodForInt extends MethodCode   private final static MethodParameter param = new MethodParameter(SimpleFileIterator class parser );  public MethodForInt(Class type CodeBuilder builder)  super(type builder);    public MethodParameter[] getInputParameters()  return new MethodParameter[]  param  ;   cha138/Article/program/Java/hx/201311/25959

相关参考

知识大全 利用spring2.5和Reflection简化测试中的mock[3]

利用spring2.5和Reflection简化测试中的mock[3]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶

知识大全 利用spring2.5和Reflection简化测试中的mock[2]

利用spring2.5和Reflection简化测试中的mock[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶

知识大全 利用spring2.5和Reflection简化测试中的mock[1]

利用spring2.5和Reflection简化测试中的mock[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶

知识大全 Java反射机制中常用API

Java反射机制中常用API  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Class是Refl

知识大全 java性能优化-之一

  .对象的生成和大小的调整  JAVA程序设计中一个普遍的问题就是没有好好的利用JAVA语言本身提供的函数从而常常会生成大量的对象(或实例)由于系统不仅要花时间生成对象以后可能还需花时间对这些对象进

知识大全 java api混排算法

  混排(Shuffling)      混排算法所做的正好与sort相反:它打乱在一个List中可能有的任何排列的踪迹也就是说基于随机源的输入重排该List这样的排列具有相同的可能性(假设随机源是公

知识大全 使用.NET Profiler API检查并优化程序的内存使用

使用.NETProfilerAPI检查并优化程序的内存使用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一

知识大全 Java 3D图形API

Java3D图形API  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  作者TnkLuo  E_m

知识大全 Java常用的加密 解密 数字签名等API

Java常用的加密解密数字签名等API  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  常用API

知识大全 比较JAVA的两个设备访问API

比较JAVA的两个设备访问API  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在最近的一次研讨