java进阶之java的反射机制

来源:互联网 发布:linux系统排行榜 2017 编辑:程序博客网 时间:2024/05/17 23:34

1.反射机制简介

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

Java反射机制主要提供了以下功能

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;
  • 生成动态代理。

下面,我们通过代码来看一下反射的厉害之处。

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

package com.mystery.refl;import java.sql.Date;public class Person {    private int age;    private String name;    private Date birthday;    public Person() {        super();    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    public void sayChina(){        System.out.println("hello ,china");    }    public void sayHello(String name, int age){        System.out.println(name+"  "+age);    }    @Override    public String toString() {        return "姓名:"+name+"       生日:"+birthday;    }}

这是一个简单的pojo类,接下来的代码都会用到这个类。

public class TestReflect {    @Test    public void test1(){        Person p = new Person();        //暂时先这样写,下面的代码会使用反射的方法来创建对象        String className = p.getClass().getName();        System.out.println(className);    }}//打印结果:com.mystery.refl.Person

通过对象的getClass()我们可以获得对象的运行时类(java.lang.Class),这个方法定义在java.lang.Object中。

在java中,所有类的对象其实都是Class的实例。

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

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

@Testpublic void test2(){    Class<?> test1=null;    Class<?> test2=null;    Class<?> test3=null;    try {        test1=Class.forName("com.mystery.refl.Person");        //一般都会用这种方式    } catch (ClassNotFoundException e) {        e.printStackTrace();    }    test2=new Person().getClass();    test3=Person.class;    System.out.println("类名   "+test1.getName());    System.out.println("类名   "+test2.getName());    System.out.println("类名   "+test3.getName());}打印结果://com.mystery.refl.Person//com.mystery.refl.Person//com.mystery.refl.Person

这里产生的不是Person对象,而是Class对象!

4.在运行时判断任意一个类所具有的成员变量

    @Test    public void test3(){        Class<?> test=null;        try {            test=Class.forName("com.mystery.refl.Person");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        // 取得本类的全部属性        Field[] field = test.getDeclaredFields();        for (int i = 0; i < field.length; i++) {            // 权限修饰符            int mo = field[i].getModifiers();            String priv = Modifier.toString(mo);            // 属性类型            Class<?> type = field[i].getType();            System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";");        }    }    //打印结果    //private int age;    //private java.lang.String name;    //private java.sql.Date birthday;

这里通过java.lang.reflect.Field类的方法获得到了Person类中的属性,简单总结一下Field类的几个常用方法

返回类型 方法名 作用 Object get(Object obj 返回指定对象上此 Field 表示的字段的值 String getName() 返回此 Field 对象表示的字段的名称 void set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值 Class getType() 返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型


博客最后的小案例我们会用到这些方法。

5.在运行时调用任意一个类所具有的方法

    @Test    public void test4(){        Class<?> test=null;        try {            test=Class.forName("com.mystery.refl.Person");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        try{            //调用Person类中的sayChina方法            Method method=test.getMethod("sayChina");            method.invoke(test.newInstance());            //调用Person的sayHello方法            method=test.getMethod("sayHello",                    String.class,int.class);            method.invoke(test.newInstance(),"jack",21);        }catch (Exception e) {            e.printStackTrace();        }    }    //打印结果    //hello ,china    //jack  21

这里用到了java.lang.reflect.Method中的方法。

6.查看某一对象的其他属性

@Test    public void test5(){        Class<?> test=null;        try {            test=Class.forName("com.mystery.refl.Person");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        //获得类所实现的接口        Class<?> intes[]=test.getInterfaces();        for (int i = 0; i < intes.length; i++) {            System.out.println("实现的接口   "+intes[i].getName());        }        //获得类所继承的父类        Class<?> temp=test.getSuperclass();        System.out.println("继承的父类为:   "+temp.getName());        //获得类中所有的构造函数        Constructor<?>cons[]=test.getConstructors();        for (int i = 0; i < cons.length; i++) {            System.out.println("构造方法:  "+cons[i]);        }    }

7.通过反射,给某个对象赋值

    @Test    public void test6(){        Class<?> test=null;        try {            test=Class.forName("com.mystery.refl.Person");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        Person per=null;        try {            per=(Person)test.newInstance();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }        per.setName("jack");        per.setBirthday(new Date(95, 11, 27));;        System.out.println(per);    }    //打印结果    //姓名:jack       生日:1995-12-27

注意:此时,Person类中必须含有无参构造函数。除此之外,还可以通过直接调用对象的构造函数来进行赋值。

8.一个小案例

下面通过一个小案例来整合一下反射。

案例:利用反射,来改变person中各属性的值。

    @Test    public void test7() {        Person p = new Person();        p.setAge(20);        p.setBirthday(new Date(95, 11, 27));        p.setName("jack");        Field[] fields = p.getClass().getDeclaredFields();        for (int i = 0; i < fields.length; i++) {            Field f = fields[i];            f.setAccessible(true);            try {                Object value =  f.get(p);                if (value != null) {                    f.set(p, deal(value));                }            } catch (IllegalArgumentException e) {                e.printStackTrace();            } catch (IllegalAccessException e) {                e.printStackTrace();            }        }        System.out.println(p);        System.out.println(p.getAge());    }    private Object deal(Object value) {        if (value instanceof Integer) {            return 50;        } else if (value instanceof String) {            return "tom";        } else if (value instanceof Date) {            return new Date(1,1,1);        }        return value;    }//打印结果//姓名:tom       生日:1901-02-01//50

可以看到,我们已经将p对象的属性值全部修改了。

9.题外话

也许有人会说,我直接p.setAge(),p.setName()不就可以了?为什么非要写这么多呢?

那么我问你,如果Person类中有100个属性呢?也一个一个写?当然,这个例子举得不是特别好,我只是想通过一段代码来讲解如何使用java的反射。

使用反射可以使你的代码更加灵活,不用将代码写死,还可以直接从配置文件中加载信息,极大地提高了编程效率。

关于动态代理,之后我会专门写一篇文章来讲解。

下一篇文章我会用反射写一个通用的dao类,为什么会想到数据库呢,因为第一次接触反射是在学数据库连接时遇到的(class.forName(“com.jdbc.driver.mysql”))。。。

1 0
原创粉丝点击