浅析Java反射机制

来源:互联网 发布:青果软件教务系统 编辑:程序博客网 时间:2024/05/24 06:42

前言

一直想写一篇有关Java反射机制的文章,今天终于下定决定心,当然这只是最基础的有关反射的内容。

什么是反射机制

Java对的反射机制就是在程序运行的过程中:

  • 对于任意一个类,我们都可以知道它的所有属性以及方法
  • 对于一个对象,我们可以调用它的所有属性和方法

反射机制能做什么呢?

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

package com;/** * @author 张俊强~ * @function 在运行时判断任意一个对象所属的类 * */public class TestReflect {    public static void main(String[] args) {        // TODO Auto-generated method stub        Student stu=new Student();        System.out.println("当前对象的类为:"+stu.getClass().getName());        //输出 【当前对象的类为:com.Student】    }}class Student{          //Student类}

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

反射机制获取类的三种方法如下:

package com;/** * @author 张俊强~ * @function 反射机制获取类有三种方法  */public class TestReflect {    public static void main(String[] args) throws Exception {        Class<?> class1 = null;        Class<?> class2 = null;        Class<?> class3 = null;        //第一种 通过全类名获取 用的比较多        class1 = Class.forName("com.Student");        //第二种 直接通过类名.Class的方式得到        class2 = Student.class;        //第三种 通过对象的 getClass()方法获取 用的较少        class3 = new Student().getClass();        System.out.println(class1.getName());        System.out.println(class2.getName());        System.out.println(class3.getName());        /**         * 输出结果:         * com.Student         * com.Student         * com.Student         * */    }}class Student {}

选用第一种方法实例化一个类(一)
注:该方法只有一个简单的sayHello()方法,且代码相对比较容易理解

package com;/** * @author 张俊强~ * @function 选用第一种方法实例化一个类(方法一)  */public class TestReflect {    public static void main(String[] args) throws Exception {        Class<?> class1 = null;        //第一种 通过全类名获取 用的比较多        class1 = Class.forName("com.Student");        //第一种方法实例化一个对象        Student stu=(Student) class1.newInstance();        //调用该对象的sayHello方法        stu.sayHello();    }}class Student {    //在该类中新建一个sayHello方法    public void sayHello() { // sayHello方法        System.out.println("hello!");    }}

选用第一种方法实例化一个类(二)
注:
这次我们要做一些相对比较复杂一点的工作了:
(1)在该Student类中添加属性姓名,并且添加构造函数进行赋值
(2)利用两个不同的构造函数来分别初始化对象

首先Student类我们设计成这个样子

class Student {    private String stuName; // 该类有一个属性 学生姓名    // 无参构造函数    public Student() {    }    // 有参构造函数    public Student(String stuName) {        this.stuName = stuName;    }    public void sayHello() { //sayHello方法        if (this.stuName == null) {     // 如果调用的是第一个无参构造函数            System.out.println("无名氏" + "在说:hello!");        } else {                        //如果调用的是第二个有参构造函数            System.out.println(this.stuName + "在说:hello!");        }    }}

然后主函数方法为:

package com;import java.lang.reflect.Constructor;/** * @author 张俊强~ * @function 实例化一个类(二) */public class TestReflect {    public static void main(String[] args) throws Exception {        Class<?> class1 = null;        // 第一种 通过全类名获取 用的比较多        class1 = Class.forName("com.Student");        // 得到全部的构造函数        Constructor<?> cons[]=class1.getConstructors();        for(int i=0;i<cons.length;i++){            Class<?> paras[]=cons[i].getParameterTypes();   //获取当前构造函数的所有的参数            for(int j=0;j<paras.length;j++){                System.out.print(paras[j].getName());       //打印所有的参数类型            }            System.out.println();        }        /**         * 输出结果[]内的为注释说明:         * [第一个构造函数]:         * [第二个构造函数]:java.lang.String         * */        //通过第一种勾账函数实例化Student 即:无名氏        Student stu1=(Student) cons[0].newInstance();        //通过第二种方式实例化Student        Student stu2=(Student) cons[1].newInstance("北电侯亮平");        //分别调用sayHello 方法        stu1.sayHello();        stu2.sayHello();        /**         * 输出结果:         * 无名氏在说:hello!         * 北电侯亮平在说:hello!         * */    }}

在运行时获取任意一个类的所有属性和方法

首先我们先明确getDeclaredFields()getFields()的区别:
getDeclaredFields():获取当前类的所有属性
getFields():获取当前类以及其父类的所有公有属性

获取一个类的所有属性(一)

我们将Student类的属性增加的稍微多一点

class Student {    private String stuName;     //学生姓名    private Integer stuAge;     //学生年龄    private Date stuBirthday;   //学生生日}

主函数获取对应的属性

package com;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Modifier;import java.util.Date;/** * @author 张俊强~ * @function 获取某个类的全部属性 */public class TestReflect {    public static void main(String[] args) throws Exception {        Class<?> class1 = null;        //通过全类名获取类对象        class1 = Class.forName("com.Student");        // 得到Student类的全部属性        Field[] fields=class1.getDeclaredFields();        System.out.println("修饰符\t类型\t属性名称");        for(int i=0;i<fields.length;i++){            //获取权限修饰符            int moIndex=fields[i].getModifiers();            String modifier=Modifier.toString(moIndex);            //获取属性的类型            Class<?> type=fields[i].getType();            String typeName=type.getName();            //显示属性详情            System.out.println(modifier+"\t"+typeName+"\t"+fields[i].getName());        }        /**         * 输出结果:         * 修饰符    类型                属性名称         * private  java.lang.String    stuName         * private  java.lang.Integer   stuAge         * private  java.util.Date      stuBirthday         * */    }}

获取一个类的所有属性(二)
注:这里我们稍微复杂一点:
(1)让该类继承一个父类或者实现某一接口
(2)这里我们以继承为例【两者方法一样】
(3)这里只能获取公有的属性

代码与前面的基本差不多,如下:

package com;import java.lang.reflect.Field;import java.lang.reflect.Modifier;/** * @author 张俊强~ * @function 获取某个类的全部属性(包括父类) */public class TestReflect {    public static void main(String[] args) throws Exception {        Class<?> class1 = null;        //通过全类名获取类对象        class1 = Class.forName("com.Student");        //得到Student类的全部属性(public 只能是公有的)        Field[] fields=class1.getFields();        System.out.println("修饰符\t类型\t属性名称");        for(int i=0;i<fields.length;i++){            //获取权限修饰符            int moIndex=fields[i].getModifiers();            String modifier=Modifier.toString(moIndex);            //获取属性的类型            Class<?> type=fields[i].getType();            String typeName=type.getName();            //显示属性详情            System.out.println(modifier+"\t"+typeName+"\t"+fields[i].getName());        }        /**         * 输出结果:         * 修饰符  类型                                        属性名称         * public   java.lang.String    stuGrade         * public   java.lang.String    name         * public   java.lang.Integer   age         * */    }}//父类为Personclass Person{    public String name;     //姓名    public Integer age;     //年龄}//Student类继承Person类class Student extends Person{    public String stuGrade;     //学生年级}

获取一个类的所有方法

首先我们先明确getDeclaredMethods()getMethods()的区别:
getDeclaredMethods():获取当前类的所有方法
getMethods():获取当前类以及其父类的所有公有方法

程序代码(一)

package com;import java.lang.reflect.Method;import java.util.Date;/** * @author 张俊强~ * @function 获取某个类的全部方法 */public class TestReflect {    public static void main(String[] args) throws Exception {        //获取类对象        Class<?> class1  = Class.forName("com.Student");        //得到Student类的全部方法        Method[] methods=class1.getDeclaredMethods();        System.out.println("修饰符\t返回值\t方法名称");        for (Method method : methods) {            System.out.println(method);        }    }}//该Student类有两个方法 1.sayHello 2.获取当前时间class Student{    public void sayHello(){        System.out.println("Hello");    }    public Date getMomentTime(){        return new Date();    }}

输出结果:

修饰符 返回值 方法名称public  java.util.Date  getMomentTimepublic  void    sayHello

程序代码(二)
我们将上面的getDeclaredMethods()换为getMethods(),得到输出结果如下

修饰符 返回值 方法名称public java.util.Date com.Student.getMomentTime()public void com.Student.sayHello()public final void java.lang.Object.wait() throws java.lang.InterruptedExceptionpublic final void java.lang.Object.wait(long,int) throws java.lang.InterruptedExceptionpublic final native void java.lang.Object.wait(long) throws java.lang.InterruptedExceptionpublic 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()

我的Student类没有继承什么东西啊,为什么会多出来这么多的方法呢?
仔细观察这些方法会发现,全部都是java.lang.Object里面的方法,这时候我们就知道,我们写的类会默认继承一个Object类。

生成动态代理

首先,我们先解决一下几个问题。

【1】什么是代理?
为其他对象(委托类的对象)提供一种代理(代理类)以控制对这个对象(委托类的对象)的访问。

【2】什么是静态代理?
代理类在程序运行前就已经编写好。

【3】什么是动态代理?
在程序运行过程中动态创建代理类。

【4】怎样使用动态代理?
在使用动态代理时候,我们需要在委托类和代理类之间定义一个中间类,该类实现InvocationHandler接口:

//InvocationHandler 接口定义public interface InvocationHandler {     Object invoke(Object proxy, Method method, Object[] args); }

我们来理解一下该接口:
(1)通过名称可以知道该接口为 请求处理器,也有称为调用处理器
(2)invoke方法中的参数分别为:proxy:代理类对象; method:调用代理类的方法; args:该方法的参数。

接下来我们看看怎样用Java的反射机制来生成动态代理!

package com;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * @author 张俊强~ * @function 生成动态代理 */public class TestReflect {    public static void main(String[] args) throws Exception {        MyInvocationHandler demo = new MyInvocationHandler();        Student sub = (Student) demo.bind(new StudentImpl());        sub.sayHello("北电侯亮平");    }}// 定义学生接口interface Student {    public void sayHello(String name);}// 定义学生class StudentImpl implements Student {    public void sayHello(String name) {        System.out.println("sayHello");        System.out.println("hello " + name);    }}//定义我的请求(调用)处理器class MyInvocationHandler implements InvocationHandler {    private Object obj = null;    public Object bind(Object obj) {        System.out.println("bind");        this.obj = obj;        //获取代理类实例 Student         //三个参数分别为:        //1.类加载器        //2.代理类实现的所有接口        //3.我们自定义的请求处理器        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);    }    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("invoke");        Object temp = method.invoke(this.obj, args);        return temp;    }}

最后

上面就是一些最基本的有关Java反射机制的知识点了!那么Java反射机制有哪些应用呢?