Java反射机制

来源:互联网 发布:unity3d 钱币资源 编辑:程序博客网 时间:2024/05/04 08:00

介绍

Java反射机制是很多框架使用的基础.

当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。
我们认为java并不是动态语言,但是它却有一个非常突出的动态相关机制,俗称:反射。

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

反射机制主要提供了以下功能:
1,在运行时判断任意一个对象所属的类;
2,在运行时构造任意一个类的对象;
3,在运行时判断任意一个类所具有的成员变量和方法;
4,在运行时调用任意一个对象的方法;
5,生成动态代理。

Demo

为了学习,我做了一个测试的demo:
基本框架如下:

public class ReflectionTest {    public static void main(String[] args) {        test7();    }    /****测试方法****/}class F{    public String name;    public int id;    public F(){    }    public F(String name,int id){        this.name=name;        this.id=id;    }} 

F是用来做例子的类,main函数里调一个个测试的demo,这样就只需要建一个文件了。下面是一个一个实验:

Test1:

    //第一个实验,了解Class类的概念,Java中"万物皆为class",java.lang包中的位置说明了他的大佬地位    //本实验,将会练习如何动态获得一个对象或者一个类的类名,让你更将深入地了解Class    static void test1(){        F f=new F();//定义和初始化一个类对象        Class c1=F.class;//定义一个Class对象,初始化为F.class,                        //很多博客在这一点上解释为,class是F的一个静态变量,或者说每一个类都有一个隐式的class域                        //这似乎挺对,也有助于理解,然而我有点不同意见,                        //如果class是一个静态变量,那么它的实例也有这个变量,然而实际上,当我输入Class c2=f.class的时候,是会报错的                        //因此我认为这句话就是把F.class本身的实体赋予了c1,在Java编译时就加载进去.        Class c2=f.getClass();//通过实例对象的getClass方法也可以得到类的实体,值得说明的是这个getClass()是Object类的方法,返回这个对象的类型类,好绕                        //有趣吧,由此我们更深地了解“万物皆为class”这句话,Class is a class!!        Class c3=null;        try {            c3=Class.forName("F");//第三种获取类型类的方式Class.forClass("XXXX")        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        System.out.println(c1);        System.out.println(c2);        System.out.println(c3);        System.out.println(c1==c2);        System.out.println(c2==c3);//从这里看出绝对地址相同,指向同一个东西    }

Test2

    //通过类型类来初始化实例    static void test2(){        Class c=F.class;        F f=null;        try {            f=(F)c.newInstance();//newInstance是Class类的方法,返回一个新的泛型对象,强制转型为F对象            //这句话如果改为f=f.getClass().newInstance()不需要转型        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }        System.out.println(f);        System.out.println(f.getClass());        System.out.println(f.getClass().getName());    }

Test3

    //为了加深实验二印象,做了实验三,发现重新初始化前后的绝对地址发生变化,确定确实初始化了一个新实例,改变了f的引用    static void test3(){        F f=new F();        System.out.println(f);        try {            f=f.getClass().newInstance();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }        System.out.println(f);    }

Test4

    //实验四,    static void test4(){        Class c1=String.class;        Object c2=void.class;        Class c3=void.class;        Class c4=int.class;        System.out.println(c1.getName());//通过Class的getName方法可以获得类的名称,        System.out.println(c1.getSimpleName());//getSimpleName获取不含包完整路径的类名        System.out.println(c2.getClass().getName());//如果是对象需要先获得为对应的类型类        System.out.println(c3.getName());//我们会发现void也有一个类型        System.out.println(c4.getName());//int是基本数据类型,没有所属的包,void也是如此    }

Test5

    //实验五,动态获取类型方法    public static void test5(){        ReflectionTest rt=new ReflectionTest();        Method[] ms=rt.getClass().getMethods();//Class的getMethods()方法,返回类型的所有共有方法        //Method[] ms=rt.getClass().getDeclaredMethods();//把上一行替换成这个看看输出的方法有什么区别        for(Method m:ms){            System.out.println(m);            System.out.println(m.getName());//method.getName()获取方法名            Class returnType=m.getReturnType();//method.getReturnType()获取返回参数类型            System.out.println(returnType);            System.out.println(returnType.getName());//获取返回参数类型的名字            Class[] parameters=m.getParameterTypes();//method.getParameters获取方法传入参数的类型            for(Class p:parameters){                System.out.print(p+",");            }            System.out.println();        }    }    //实验五的辅助函数,    //这个函数的返回类型输出如下:int,class [I,class [D,class [Ljava.lang.String;,class [Lcom.way.reflection.F;,    //这是描述标识字符,就是将对象转换成的字节码    public static int test5add(int a,int[] b,double[] c,String[] d,F[] e){        return 0;    }

描述标识字符就是将.java文件编译成.class文件后对象转换成的字节码。表示字符所代表的含义如下:

这里写图片描述

Test6

    //实验六,获取成员变量    static void test6(){        F ff=new F("test",1);        Class c=F.class;        Field[] fields=c.getFields();        for(Field f:fields){                try {                    System.out.println(f.get(ff));//field.get(Object obj)获取对象的对应成员变量对象(Object)                } catch (IllegalArgumentException e) {                    e.printStackTrace();                } catch (IllegalAccessException e) {                    e.printStackTrace();                }                System.out.println(f.getType());//field.获取类型成元变量的类型类        }    }

Test7

    //实验七    static void test7(){        Class c=F.class;        Constructor[] cs=c.getConstructors();        for(Constructor constructor:cs){            System.out.println(constructor.getName());            Class[] parameters=constructor.getParameterTypes();            if(parameters.length==0){                System.out.println("No parameter constructor");            }else{                for(Class parameter:parameters){                    System.out.println(parameter.getName());                }            }        }    }

Test8

反射可以拿到一个类所有的方法和属性,包括父类和接口。很多时候我们不想获取父类和接口的东西,只想要本类中声明的属性和方法。于是就有了Class.getDeclaredXXXX()的方法,在前面试验过的各种get方法中间插入Declared,就可以获取本类的方法,实验8就是为了说明这件事。

为了说明问题,需要对F类稍作改动,就是需要F继承任意一个类,或者实现任意的接口,在这里我让他继承了Thread类,其他都不变。

class F extends Thread{
    //实验8,测试Declared的get方法    static void test8(){        Class c=null;        try {            c=Class.forName("F");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        System.out.println(c.getMethods().length);        System.out.println(c.getDeclaredMethods().length);    }

输出结果

500

可以得知,Thread有50个公共方法被F类继承了。类似的Declared的get方法概不赘述了。

总结

**获取类类型:**Class c=F.class;Class c=Class.forName("F");Class c=f.getClass(); //Object.getClass()**获取类实例:**F f=new F(); //非反射做法F f=c.newInstance(); //Class.newInstance()**获取类名称:**String fullName=c.getName();String simpleName=c.getSimpleName();**获取类方法:**Method method=c.getMethod(String name,Class<?>... parameterTypes); //java.lang.reflect.MethodMethod[] methods=c.getMethods(); //java.lang.reflect.Method[]Method[] methods=c.getDeclaredMethods();method.getName(); //Stringmethod.getParameterTypes(); //Class[]method.getParameterCount(); //intmethod.getReturnType(); //Class**获取类属性:**Field field=c.getField(String name); //java.lang.reflect.FieldField[] field=c.getFields(); field.getName(); //Stringfield.getType(); //Classfield.get(obj); //Object (the field object of obj)**获取构造器:**Constructor constructor=c.getConstructor(Class<?>... parameterTypes); //java.lang.reflect.constructorConstructor[] constructors=c.getConstructors(); constructor.getName() constructor.getParameterTypes() //Class[]**Declared方法**getDeclaredXXX(); //获取本类的属性,方法构造器,等等

以上的方法只是一部分,详细可以看源码。

参考:
http://www.jianshu.com/p/6277c1f9f48d
http://www.jianshu.com/p/b560b30726d4
这位博主文章写得挺好

0 0