JAVA中的反射机制理解与浅析

  • Post author:
  • Post category:java


BS53项目用到了java反射来获取自定义的控件,继而将其实例化并将其展示在页面,实现了只需要配置一个配置文件就可以实现整个页面的展示,而且支持5中不同风格的配置。基本全部依赖于反射技术,现在我们就去简单的了解一下反射技术。

(后文附JDK1.6API和示例源码!)

反射机制是什么?

有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,在刚刚学jdbc时用过一行代码,

 Class.forNa("com.mysql.jdbc.Driver.class").newInstance();

但是那时候只知道那行代码是生成驱动对象实例,并不知道它的具体含义。就知道必须要写这一句。


反射机制:


Java反射是Java被视为动态(或准动态)语言的一个关键性质。

这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。


Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。

换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。现在很多开框架都用到反射机制,hibernate、struts都是用反射机制实现的。安卓上现在的通过反射操作注解,通过反射操作泛型,都是一些很棒的示例。线面让我们简单的去了解一下Java反射。

JDK中提供的Reflection API有哪些?

Java反射相关的API在包java.lang.reflect中,JDK 1.6.0的reflect包如下图:

JAVA反射机制提供了什么功能?

  • 在运行时判断任意一个对象所属的类

  • 在运行时构造任意一个类的对象

  • 在运行时判段任意一个类所具有的成员变量和方法

    +

    在运行时调用任一个对象的方法

    +在运行时创建新类对象

在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。

下面的是我们定义的测试类。里面有private,public,protected和默认方法,

下面贴上我们的代码结构(代码多,在文末有下载地址)

开始我们的反射之旅

1/首先获取类的Class对象

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。获取类的Class对象有多种方式,进入我们的API查看一下:


其中:使用Class类中的forName()静态方法; (最安全/性能最好)

2、获取类的Fields

可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。JAVA 的Class类提供了几个方法获取类的属性。

代码简单示例:

    Class<?> className = Student.class;
        System.out.println("-------------Fields  开始----------------");
        // 使用getDeclaredFields获取属性 是声明为public的属性,包括父类中定义
        Field[] fields = className.getFields();
        for (Field f : fields) {
            System.out.println(f);
        }

        System.out.println("-------------Fields----------------");

        // 使用getDeclaredFields获取属性 返回的是指定类定义的所有定义的属性,不包括父类的
        fields = className.getDeclaredFields();
        for (Field f : fields) {
            System.out.println(f);
        }
        System.out.println("-------------Fields  获取完成----------------");

打印结果:

-------------Fields  开始----------------
public int com.ming.javareflect.Student.grade
public static final java.lang.String com.ming.javareflect.Behavior.TAG
public java.lang.String com.ming.javareflect.People.sex
public java.lang.String com.ming.javareflect.People.appearance
-------------Fields----------------
private java.lang.String com.ming.javareflect.Student.name
private java.lang.String com.ming.javareflect.Student.className
public int com.ming.javareflect.Student.grade
private java.lang.String com.ming.javareflect.Student.TAG
-------------Fields  获取完成----------------

3、获取类的Method

通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法

Class类提供了几个方法获取类的方法。

代码简单示例:

fields = className.getDeclaredFields();
        for (Field f : fields) {
            System.out.println(f);
        }
        System.out.println("-------------Fields  获取完成----------------");
        System.out.println("-------------Methods  开始----------------");
        // 使用getMethods获取函数
        Method[] methods = className.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
        System.out.println("-----------Methods--------------");
        // 使用getDeclaredMethods获取函数
        methods = className.getDeclaredMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
        System.out.println("-------------Methods  完成----------------");

打印结果:

-------------Methods  开始----------------
public void com.ming.javareflect.Student.run()
public java.lang.String com.ming.javareflect.Student.getName()
public void com.ming.javareflect.Student.setName(java.lang.String)
public java.lang.String com.ming.javareflect.Student.getClassName()
public void com.ming.javareflect.Student.setClassName(java.lang.String)
public int com.ming.javareflect.Student.getGrade()
public void com.ming.javareflect.Student.setGrade(int)
public void com.ming.javareflect.Student.eat()
public void com.ming.javareflect.Student.communicate()
public boolean com.ming.javareflect.Student.love()
public void com.ming.javareflect.People.setAge(int)
public void com.ming.javareflect.People.setSex(java.lang.String)
public void com.ming.javareflect.People.setBirthday(java.util.Date)
public void com.ming.javareflect.People.setAddress(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
-----------Methods--------------
public void com.ming.javareflect.Student.run()
public java.lang.String com.ming.javareflect.Student.getName()
public void com.ming.javareflect.Student.setName(java.lang.String)
public java.lang.String com.ming.javareflect.Student.getClassName()
public void com.ming.javareflect.Student.setClassName(java.lang.String)
public int com.ming.javareflect.Student.getGrade()
public void com.ming.javareflect.Student.setGrade(int)
private void com.ming.javareflect.Student.toPlayer()
protected void com.ming.javareflect.Student.justPrint(java.lang.String)
public void com.ming.javareflect.Student.eat()
public void com.ming.javareflect.Student.communicate()
public boolean com.ming.javareflect.Student.love()
-------------Methods  完成----------------

4、获取类的Constructor

通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例

Class类提供了几个方法获取类的构造器。

简单代码示例:

System.out.println("-------------Constructor  开始----------------");
        // 使用getConstructors获取构造器    
        Constructor<?>[] constructors = className.getConstructors();  
        for (Constructor<?> m : constructors)  
        {  
            System.out.println(m);  
        }  

        System.out.println("-------------Constructor ----------------");

        // 使用getDeclaredConstructors获取构造器     
        constructors = className.getDeclaredConstructors();  
        for (Constructor<?> m : constructors)  
        {  
            System.out.println(m);  
        }  
        System.out.println("-------------Constructor  完成----------------");

打印结果:

-------------Constructor  开始----------------
public com.ming.javareflect.Student()
public com.ming.javareflect.Student(java.lang.String,java.lang.String,int)
-------------Constructor ----------------
public com.ming.javareflect.Student()
public com.ming.javareflect.Student(java.lang.String,java.lang.String,int)
-------------Constructor  完成----------------


获取方法,和构造方法,不再继续详细描述,只来看一下关键字

5、新建类的实例

通过反射机制创建新类的实例,有几种方法可以创建

简单示例代码如下:

    System.out.println("-------------newInstance  开始----------------");
        try {
            Class clazz = Class.forName("com.ming.javareflect.People");
            /**
             * 第一种方法创建对象
             */
            // 创建对象
            People p = (People) clazz.newInstance();
            // 设置属性
            p.setName("张三大侠");
            p.setAge(166);
            p.setSex("男");
            System.out.println(p.toString());

            /**
             * 第二种方法创建
             */
            // 获取构造方法
            Constructor c;
            // 创建对象并设置属性
            c = clazz.getDeclaredConstructor(String.class, int.class,String.class);
            People p1 = (People) c.newInstance("李四", 699, "男");
            System.out.println(p1.toString());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("-------------newInstance  完成----------------");

打印结果如下:

-------------newInstance  开始----------------
People [name=张三大侠, age=166, sex=男, birthday=null, address=null, appearance=null, TAG=People]
People [name=李四, age=699, sex=男, birthday=null, address=null, appearance=null, TAG=People]
-------------newInstance  完成----------------

6、调用类的函数

通过反射获取类Method对象,调用Field的Invoke方法调用函数。

System.out.println("-------------Field的Invoke  开始----------------");

        try {
            Object inst;
            inst = className.newInstance();
            Method printMethod = className.getDeclaredMethod("justPrint", String.class); 
            printMethod.setAccessible(true);//如果失败是由于没有权限调用private函数,这里需要设置Accessible为true
            printMethod.invoke(inst, "hasagei"); 
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 

        System.out.println("-------------Field的Invoke  完成----------------");

打印结果:

-------------Field的Invoke  开始----------------
People   Student  hasagei
-------------Field的Invoke  完成----------------

7、设置/获取类的属性值

通过反射获取类的Field对象,调用Field方法设置或获取值

简单示例代码:

System.out
                .println("-------------反射获取类的Field对象,调用Field方法设置或获取值----------------");

        try {
            Object inst;
            inst = className.newInstance();
            Field intField = className.getField("grade");
            intField.setInt(inst, 3);
            int value = intField.getInt(inst);
            System.out.println(value + "");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out
                .println("-------------反射获取类的Field对象,调用Field方法设置或获取值----------------");

打印结果:

-------------反射获取类的Field对象,调用Field方法设置或获取值----------------
3
-------------反射获取类的Field对象,调用Field方法设置或获取值----------------

反射加配置文件,使我们的程序更加灵活:

BS53中的反射+配置文件的使用:当时用的配置文件是app.config文件,内容是XML格式的,里边填写链接数据库的内容:

比如:

在这里面写好配置文件,用反射获取里面的配置,然后加载出整套桌面。

那么我们写几份模版,在配置文件的内容改一下,或者加条件选择一下即可,带来了很大的方便。

当然了,JAVA中其实也是一样,只不过这里的配置文件为.properties,称作属性文件。通过反射读取里边的内容。这样代码是固定的,但是配文的内容我们可以改,这样使我们的代码灵活了很多!

综上为,JAVA反射的再次学习,灵活的运用它,能够使我们的代码更加灵活,但是它也有它的缺点,就是运用它会使我们的软件的性能降低,复杂度增加,所以还要我们慎重的使用它。



百度云示例源码和JDK1.6API下载地址



版权声明:本文为zhcswlp0625原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。