`
songlixiao
  • 浏览: 22642 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
最新评论

java反射在项目中的应用

    博客分类:
  • java
阅读更多

  Java反射(reflect)是开发过程中一种常用的手段,常常被用在处理一些感觉有共性但看起来又好像没法抽象的功能上.在OECP项目开发当中,我们在很多地方用到了反射,其中对实体类进行了分层抽象封装的过程中就有一些使用.本文将以重写equals方法为例,简单介绍一下java反射的应用.

  先大体介绍一下我们的实体封装的结构.从UML图中我们可以看到顶级SuperEO类作为整个实体层次的顶端,它包含了所有实体类所共有的方法和属性,比如:克隆方法.我们知道克隆方法的默认实现是Object中的,并且为浅克隆.但浅克隆通常对于我们来说没什么意义,所以我们需要实现一个深克隆的方法(本文主要是说java反射的应用.深克隆和浅克隆的区别不了解的朋友可以去google一下),这个方法为所有实体类所共有.像这样需要所有实体共有的方法还有equals(比较),getAttributeValue(根据字段名得到字段值)等等.SuperEO下有两个分支,分别为BaseEO和BaseVO.BaseEO为可持久化实体的父类,包括跟持久化有关的一些属性和方法.BaseVO为非持久化实体父类,此类暂时没有自己的方法和属性,其存在的目的是预留有备扩充.由此,系统中所有的实体类都从这两个分支派生而来.下面几个类就不详细介绍了,毕竟此文的目的不是介绍实体抽象方案的.以后我们在其他地方再对这个实体结构做详细分析说明.

   我们看到在实体继承关系之外,存在一个叫做EOUtility的类,此类是个EO的辅助工具类,SuperEO依赖这个工具类,来实现一些通用方法.我们所要说的java反射的应用,也就集中在这个工具类中.

   这个类中,我们使用java反射实现了好多通用的功能.在这里我就不每个方法都说明了,只简单介绍其中一个来说一下java反射的用法吧.equals方法是我们java开发人员平时比较常用的一个方法,用来比较两个对象是否相等.此方法的默认实现为Object类中的实现,而默认实现的原理呢,则是按内存地址进行比较,也就是说,如果我们创建了两个内部值完全相同的对象,在我们使用equals对它们进行比较时返回的结果会是false,因为他们的内存地址是不同的.显然这不是我们想要的结果,我们需要的是,将两个对象的内部属性值进行逐一对比,全部相同则返回true,否则为false.为了实现这个目的,我们应该怎么去做呢?下面我们分析一下.

   为了使所有的子类都拥有这个方法,我们必须将这个方法定义在顶级超类SuperEO中.在两个对象进行比较时,我们需要获取对象中所有的属性字段,以及这些字段的get方法,而后使用get方法得到属性值,对这些值进行比较.可是equals方法我们要在SuperEO中实现,而SuperEO的子类是由其他的开发人员定义的,其内部有多少属性字段,都叫什么名字,在我们的SuperEO中是不知道的.既然这些都不知道,我们又怎么能比较这些值呢? 看起来这是个问题.

   但是这个问题能不能解决呢? 能!这就要用到我们所说的java反射机制了.反射机制简单的说是java提供给开发人员用来对类和方法属性进行操作的工具.利用反射机制,我们是可以获取我们想要的属性字段,以及他们的get方法的,并且我们可以调用这些方法.这样我们的问题就解决了,下面可以开工了.我实现的步骤是这样的.

  首先,使用Class.getDeclaredFields方法得到当前类所有的属性字段,而后使用PropertyDescriptor.getReadMethod()得到他们的get方法,并将他们存入一个HashMap中,以字段名为Key,get方法作为Value.在进行字段比较时使用Method.invoke方法,循环调用这些字段的get方法取值而后比较.
代码片段:

PropertyDescriptor[] propertyDescriptors = null;    
private void buildGetterANDSetters(Class beanclass){    
    // 得到当前类字段名称    
    Field[] fields = beanclass.getDeclaredFields();    
    String fieldname = null;    
    // 拼接字段对应的方法名    
    for( Field field : fields ){    
        // 一对多字段不要参加toString,hashcode和equals方法,不需要加载,一旦加载反而会引起数据级联更新时出错!!    
        OneToMany onetomany = field.getAnnotation(OneToMany.class);    
        Transient t = field.getAnnotation(Transient.class);    
        if(onetomany != null || t != null){    
            continue;    
        }    
        fieldname = field.getName();    
        for(PropertyDescriptor property : propertyDescriptors){    
            if(fieldname.equals(property.getName())){    
                Method reader = property.getReadMethod();    
                Method writer = property.getWriteMethod();    
                if(reader!=null     
                        && !(reader.isAnnotationPresent(OneToMany.class)||    
                        reader.isAnnotationPresent(Transient.class)))    
                    hm_Geters.put(fieldname, reader);    
                if(writer!=null   
                        &&!(writer.isAnnotationPresent(OneToMany.class)||    
                        writer.isAnnotationPresent(Transient.class)))    
                    hm_Seters.put(fieldname, writer);    
            }    
        }    
    }    
    // 当前类不是 BaseEntityBean时,递归调用    
    if(!beanclass.equals(SuperEO.class)){    
        buildGetterANDSetters((Class<? extends SuperEO>)beanclass.getSuperclass());    
    }    
}    
   
 

 而后在equals方法循环调用下面这个方法进行比较:

/**   
 * 比较两个对象,指定的字段值是否相同   
 * @author slx   
 * @date 2009-7-17 上午09:51:58   
 * @modifyNote   
 * @param fieldName   
 *      需要比较的字段   
 * @param obj1   
 *      对象1   
 * @param obj2   
 *      对象2   
 * @return   
 *      值相同则为true   
 */   
private boolean equalsField(String fieldName , Object obj1 ,Object obj2){    
    try {    
        Object obj_value = null;    
        Object current_value = null;    
        Method getter = hm_Geters.get(fieldName);    
        current_value = getter.invoke(obj1, null);    
        obj_value = getter.invoke(obj2, null);    
            
        if(current_value == null && obj_value ==null ){    
            return true ;    
        }else if(current_value!=null){    
            return current_value.equals(obj_value);    
        }else if(obj_value!=null){    
            return obj_value.equals(current_value);    
        }    
            
    } catch (Exception e) {    
        throw new RuntimeException(e);    
    }     
    return false ;    
}   
 

   除equals之外通过类似这样的方式,在我们的EOUtility中我们还实现了根据字段名取值,根据字段名赋值,对象的toString方法打印出所有字段值,得到对象所有属性的名称等方法.这些方法为我们程序其他的一些功能封装时提供了可能性和方便性.比如我们需要封装一个界面表格的输出,我们只要知道当前的实体是SuperEO就可以了,而不需要知道具体是那个子类.通过getAttributeNames就可以得到所有的字段名称,通过getAttributeValue(字段名)就可以得到字段的值,而后使用循环就可以把我们想要的表格画出来了.而这一切的便捷是我们封装的父类中提供的,提供这些方法的前提则是java反射 — reflect.
   当然,java反射绝不仅仅是这么一点点功能,连同动态代理,类加载器等也都应该是属于java反射的范畴.在我们需要封装针对类的通用功能时,是很有用的.

 

提供该文档的机构为 百洋软件研究实验室 ,更多的博客文章可以到 百洋软件研究实验室博客 查看。该文档附件欢迎各位转载,但是在没有获得文章作者许可之前,不得对文章内容或者版权信息进行更改,版权归百洋软件研究实验室所有,仅此声明。

原文:http://www.po-soft.com/blog/slx/443.html

分享到:
评论

相关推荐

    Java反射在实际工作中的应用笔记

    主要介绍了Java反射在实际工作中的应用笔记,具有一定借鉴价值,需要的朋友可以参考下。

    Java反射学习和反射的应用场景干货都在这里

    写在前面:Java反射是我们做项目中必备的技能,本篇文章将重新学习反射的基本用法、反射的应用场景等。 一、Java反射定义 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于...

    demo-反射项目源码.rar_DEMO_java 反射_pulls87_算法

    反射项目,我沃尔上传demo反射,Java编程反射运用

    复习反射利用反射机制和AOP代理模式

    reflection是一系列的API,用于表示或者处理当前JVM中的类,接口和对象. java.lang.reflect/java.lang.Class 在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

    Java反射机制与框架原理

    一、课程简介 这是『Java学习指南系列』的第18篇教程 ,是Java开发的高级课程,介绍反射...〖网站开发〗系列:包含网页基础、网站入门、数据库、网站中级、FreeMarker、网站高级、项目应用、MyBatis、Redis等课程。

    Java反射机制应用实践

     Java反射机制是一个非常强大的功能,在很多大型项目比如Spring, Mybatis都可以看见反射的身影。通过反射机制我们可以在运行期间获取对象的类型信息,利用这一特性我们可以实现工厂模式和代理模式等设计模式,...

    Java课程设计项目实例《基于微服务的在线签到》子系统.pdf

    二、系统所应用的核心技术——微服务 1、单体架构的应用 (1)什么是单体架构(Monolithic Architecture)的应用 在传统的软件应用开发中,基本上都是将一个软件项目相关的功能程序代码(包含有 系统的 DO/DAO,...

    java 面试常见问题整理

    你的项目中哪里用到了泛型? 反射 何为反射? 反射机制优缺点 反射的应用场景 注解 异常 Exception 和 Error 有什么区别? Checked Exception 和 Unchecked Exception 有什么区别? Throwable 类常用方法有哪些? ...

    java JDK 实例开发宝典

    169个实例,内容涉及Java的语言基础、面向对象程序设计、数字处理、数组与集合、字符串、异常处理、文件操作、多线程、Swing编程、图形和多媒体编程、反射机制、网络程序设计、数据库编程、Applet、Java与XML、Java ...

    实验项目D、Java应用专题编程

    一、实验目的 ★专题:核心专题技术★ ...7.[选做]反射和注解——一个综合应用 ★专题:接口基础和面向接口编程★ 1.字符串处理 2.数有关类:数学Math类、随机数类Random、大数类 3.时日API 4.Java

    基于Java的XML解析与反射设计模式.doc

    关键词:xml java 在web中,多系统间数据交互一般使用webservice技术,它是一种构建应用程序的普遍模 型,可以在任何支持网络通信的操作系统中实施运行;它是一种新的web应用程序分支, 是自包含、自描述、模块化的...

    java中spring依赖注入的简单例子

    依赖注入早期叫控制反转 也可以称反射 他们的意义都相同 当某个 Java 实例 调用者 需要另一个Java 实例 被调用者 时 在传统的程序设计过程中 通常由调用者来创建被调用者的实例 而在依赖注入的模式下 创建被调用者的...

    java swing+jdbc+mysql 客户信息管理系统

    该项目中包含功能点(java导出excel文件、jcombobox省市区三级联动、jdbc中java反射的应用、swing组件用户登录,显示数据、jdbc操作mysql数据库),有对应jar包,对应sql文件。

    java联想(中文)

    2.2.3 Java中的数组 2.3 绝对不要清除对象 2.3.1 作用域 2.3.2 对象的作用域 2.4 新建数据类型:类 2.4.1 字段和方法 2.5 方法、自变量和返回值 2.5.1 自变量列表 2.6 构建Java程序 2.6.1 名字的可见性 2.6.2 使用...

    达内java培训目录

    JavaSE核心 异常处理、多线程基础、IO系统、网络编程、Java反射机制、JVM性能调优(JVM内存结构剖析、GC分析及调优、JVM内存参数优化)、Java泛型、JDK新特性 熟练掌握JavaSE核心内容,特别是IO和多线程;...

    Java面试题.docx

    16、说说你对Java反射的理解 17、说说你对Java注解的理解 18、Java中String的了解 19、String为什么要设计成不可变的? 20、Object类的equal和hashCode方法重写,为什么? 21-40题 21、List,Set,Map的区别 26...

    Thinking in Java简体中文(全)

    2.2.3 Java中的数组 2.3 绝对不要清除对象 2.3.1 作用域 2.3.2 对象的作用域 2.4 新建数据类型:类 2.4.1 字段和方法 2.5 方法、自变量和返回值 2.5.1 自变量列表 2.6 构建Java程序 2.6.1 名字的可见性 2.6.2 使用...

Global site tag (gtag.js) - Google Analytics