JAVA--reflect(反射)

来源:互联网 发布:环保部网络举报 编辑:程序博客网 时间:2024/06/14 01:02

java编程之ReFlect(反射)


  • Class类的反射
  • 方法的反射
  • 成员变量的反射
  • 构造函数的反射
  • java类加载机制


    Class类的反射

  • Class类

    在面向对象的世界里,万事万物都是对象。
    java语言中,静态的成员,普通的数据类型也是对象,类的实例就是类的对象。
    那么类是谁的对象呢?
    类是对象,类是java.lang.Class类的实力对象。
    There is a class named Class

package com.imooc.ReFlectTest;/***这段代码介绍了关于Class类的实例的三种创建方法*/public class ClassDemo1 {    public static void main(String[] args) {        //创建一个Dog类的实例对象        Dog dog = new Dog();        //Dog类也是实例对象,Dog类是Class类的实例对象        //Class类只有private权限的构造函数,只允许jvm调用!        //我Class类的实例对象,一共有3种表示方式        //第一种每个类都有一个隐含的static(静态)的成员class,可以直接调用        Class c1 = Dog.class;        //第二种,已知一个类的实例对象,可以调用getClass()方法        Class c2 = dog.getClass();        /**         * 官方上给的解释,此处的c1,c2是Dog类的(class type(类类型))         */        //结果是true,说明c1,c2都代表了Dog类的类类型,也说明了一个类只有一个Class类的一个实例对象        System.out.println(c1 == c2);        //第三种方式,调用Class类的forName方法,会有异常        Class c3 = null;        try {            //方法中写入类的全称            c3 = Class.forName("com.imooc.ReFlectTest.Dog");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        //此处依然是true,还是那句话一个类只有一个Class类的实例对象        System.out.println(c2 == c3);        /**         * 我们也可以通过类的类类型来创建该类的实例         * 即我们可以用c1 or c2 or c3 来创建一个Dog类的对象         */        try {            //类类型创建的类的实例是Object类型的,此处因为没有用泛型,所以我们需要进行强制类型转换            //前提是该类要有无参数的构造方法            Dog dog1 = (Dog)c1.newInstance();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }}class Dog{}

Class.forName(“类的全称”)

  • 不仅表示类的类类型,还表示了动态加载类
  • 区分编译和运行
  • 编译时加载的类是静态加载类,运行时加载的类是动态加载类

使用反射访问类的所有信息

代码中的注释已经详细解释了他们的作用

package com.imooc.ReFlectTest;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class Classutil {    /**     * 打印类的信息,包括类的成员函数的信息     * obj 即类的对象,此处没用泛型,所以用多态来实现     */    public static void printClassMassage(Object obj) {        //获取实际传递的obj的类类型        Class c = obj.getClass();//存在多态,实际调用时,调用的是传递的类的方法        //获取类的名字        System.out.println(c.getName());        /**         * Method方法,用来获取类的方法名         * 一个方法就是一个Method对象         * getMethods()方法获取的是所有的public的函数,包括从父类继承来的         * getDeclaredMethods()方法获取类自己声明的所有方法,不问访问权限         */        Method[] methods =  c.getMethods();//c.getDeclaredMethods();        for(int i=0; i<methods.length; i++) {            //输出方法的名字            System.out.print(methods[i].getName() + "(");            //通过方法,获取方法的参数列表            //getParameterType()方法,获取参数列表的类型的类类型            Class[] parameterType = methods[i].getParameterTypes();            //依次打印方法的参数列表            for (Class class1 : parameterType) {                System.out.print(class1.getName() + ",");            }            System.out.println(")");        }    }    public static void printFieldMessage(Object obj) {        Class c = obj.getClass();        /**         * 获取类的成员变量的信息         * 用java.lang.reflect.Field         * Field封装了关于类的成员变量的所有操作         * getFileds()方法获取所有权限为public的成员变量的信息         * getDeclaredFileds()方法获取的是该类自己声明的变量的信息         */        Field[] fileds = c.getDeclaredFields();        for (Field field : fileds) {            //得到成员变量的类型的类类型            Class fieldType = field.getType();            //typeName,成员变量的名字,即变量名            String typeName = fieldType.getName();            //fieldName,变量的类类型的名字,即变量的类型名(例:int,String)            String fieldName = field.getName();            System.out.println("typeName = " + typeName + " " +"fieldName = "+ fieldName);        }    }    public static void printConMessage(Object obj) {        Class c = obj.getClass();        //获取所有的public的构造方法        //Constructor[] cs = c.getConstructors();        //获取当前类内的所有的构造方法Constructor        Constructor[] cs = c.getDeclaredConstructors();        for (Constructor constructor : cs) {            System.out.print(constructor.getName() + "(");            Class[] parameter = constructor.getParameterTypes();            for (Class class1 : parameter) {                System.out.print(class1.getName() + ",");            }            System.out.println(")");        }    }}

通过上述代码的方法,我们可以访问任意一个类的名称以及它的所有方法的名称,参数列表以及返回值,包括构造函数!
当然除了上述的三种访问以外,reflect中还封装了很多很好的方法,我们可以在需要的时候,去查阅java.lang,Class的API


通过获取的类信息,可以做反射操作

我们通过获取的类的信息,可以方法调用对象

package com.imooc.ReFlectTest;import java.lang.reflect.Method;public class ClassDemo5 {    public static void main(String[] args) {        A a1 = new A();        //获取方法的信息的前提是获取类的信息,获取类的信息要先获取类的类类型        Class c = a1.getClass();        try {            /**             * 获取方法,由名称和参数列表来决定             * getMethod()获取public的方法             * getDeclaredMethod()获取自己声明的方法             */            Method m = c.getMethod("print", int.class, int.class);            //方法的反射调用,利用m对象进行方法的调用invoke()方法,和a1.print()的效果完全相同            //invoke(obj, new Object[])            //方法无返回值,则返回null,否则返回方法的返回值             Object o = m.invoke(a1, new Object[]{10,20});//          Object o = m.invoke(a1, 10,20);            System.out.println("================================");            Method m1 = c.getMethod("printStr", String.class, String.class);            //用方法进行反射操作//          a1.printStr("Hello", "World");            m1.invoke(a1, "hello", "World");            System.out.println("=================================");            //方法没有参数            //方法1 ,传一个空的类类型数组//          Method m2 = c.getMethod("print", new Class[]{});            //方法2,不穿参数也可以            Method m2 = c.getMethod("print");//          m2.invoke(a1, new Object[]{});            m2.invoke(a1);        } catch (Exception e) {            e.printStackTrace();        }    }}class A {    public void print(int a, int b) {        System.out.println(a + b);    }    public void printStr(String a, String b) {        System.out.println(a.toUpperCase() + "," + b.toUpperCase());    }}

通过反射我们可以理解集合泛型的本质

泛型的目的是为了防止输入错误,但只在编译时有效。

package com.imooc.ReFlectTest;import java.awt.event.FocusEvent;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;public class ClassDemo6 {    public static void main(String[] args) {        List l1 = new ArrayList();        List<String> l2 = new ArrayList<String>();        Class c1 = l1.getClass();        Class c2 = l2.getClass();        //结果为true        System.out.println(c1 == c2);        l2.add("hello");        //String类型的List不能添加int型的数,编译时无法通过//      l2.add(20);        /**         * 反射的操作都是编译之后的操作         * c1 == c2 返回值为true说明编译之后的集合是“去泛型化”的         * java集合中的泛型,是防止错误输入的,只在编译阶段有效         * 当我们绕过编译时,泛型就无效了         * 验证:通过方法的反射操作,绕过编译         */        try {            Method m = c2.getMethod("add", Object.class);            m.invoke(l2, 20);            System.out.println(l2.size());            System.out.println(l2);            /*             * 不能使用foreach循环,会出异常             * for (String string : l2) {             *      System.out.println(string);             * }             */        } catch (Exception e) {            e.printStackTrace();        }    }}
0 0
原创粉丝点击