• 反射-包括运行代码示例


    反射相信大家平时学习时用的不多但见的很多,特别是各种开源框架中,到此都是反射。编译时加载类是静态加载、运行时加载类是动态加载,动态加载可通过反射实现。

    一、定义
    反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;
    对于任意一个对象,都能够调用它的任意一个方法。
    在java 中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。
    二、功能
    在运行时判定任意一个对象所属的类;
    在运行时创建对象;
    在运行时判定任意一个类所具有的成员变量和方法;
    在运行时调用任意一个对象的方法;
    生成动态代理。
    如:Class.forName(‘com.mysql.jdbc.Driver.class’);//加载MySql 的驱动类。这就
    是反射,现在很多框架都用到反射机制,hibernate,struts ,spring等框架都是用反射机制实
    现的。

    三、反射的实现方式
    1、Class.forName(“类的路径”)
    2、类名.class
    3、对象名.getClass()
    4、如果是基本类型的包装类,则可以通过调用包装类的Type 属性来获得该包装类的Class 对象。
    ​ 例如:Class<?> clazz = Integer.TYPE;

    这个Class也称类类型,也就是说每一个 Class它也是个对象(万物皆对象),所以clazz是一个类对象

    四、实现反射的类
    1、Class:它表示正在运行的Java 应用程序中的类和接口。
    2、Field:提供有关类或接口的属性信息,以及对它的动态访问权限,如private、public等权限。
    3、Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
    4、Method:提供关于类或接口中某个方法信息。

    注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包括:方法/属性/构造方法/访问权限)都需要它来实现。

    五、Java动态加载类使用场景
    例如,你可以传一个参数,运行时判断参数为1加载A类(通过反射),参数为2加载B类,然后A、B类都实现一个接口C,这样就可以面向接口编程啦(主程序面向C编程,后面还可以继续添加C接口的实现类来扩展,符合开闭原则)

    六、反射机制的优缺点?
    优点:
    (1)能够运行时动态获取类的实例,大大提高程序的灵活性(由各框架中到此是反射可见)。
    (2)与Java 动态编译相结合,可以实现无比强大的功能。
    缺点:
    (1)使用反射的性能较低。java 反射是要解析字节码,将内存中的对象进行解析。

    七、下面不是概念,干货来啦!
    反射工具测试类

    package com.reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    /**
     * @author Guoming Zhang
     * @Description Class类的使用
     * @Date 2018/12/20
     */
    class Foo {
        void print(int a, int b) {
            System.out.println(a + b);
        }
    
        void print(String a, String b) {
            System.out.println(a + " , " + b);
        }
    }
    
    public class ReflectUtil {
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
            /***********一、反射Class类的使用*****************/
            //useOfClass();
    
            /***********二、反射获取方法信息******************/
            //printMethodMessage(new String());
    
            /***********三、反射获取成员变量********************************/
            //printFiledMessage(new String());
    
            /***********四、反射获取成员构造函数********************************/
            //printConstructorMessage(new String());
    
            /***********五、方法的反射调用********************************/
            //printMethodInvoke();
    
            /***********六、通过反射验证泛型擦除**********************************************/
            printFanXingClear();
        }
    
        //反射Class类的使用
        public static void useOfClass() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            Foo foo = new Foo();
    
            Class c1 = Foo.class;
            Class c2 = foo.getClass();
            Class c3 = Class.forName("com.reflect.Foo");
    
            System.out.println(c1 == c2);//true
            System.out.println(c2 == c3);//true
    
            //可以通过类类型创建对象
            Foo myFoo = (Foo) c3.newInstance();
            myFoo.print(1, 2); // "你好啊朋友"
        }
    
        //反射获取方法信息
        public static void printMethodMessage(Object obj) {
            //获取字节码,或称类类型
            Class c = obj.getClass();
            System.out.println("类的名称为:" + c.getName());//c.getSimpleName()则不带包名
    
            /**
             * Method : 方法对象,方法也是一个对象!万物皆对象
             * getMethods获取所有public方法,包括父类继承而来的
             * getDeclareMethods() 获取所有自己声明的方法,任何访问权限,不包父类的
             */
            Method[] ms = c.getMethods();//或c.getDeclareMethods()
            for (int i = 0; i < ms.length; i++) {
                //得到方法的返回值类型的类类型,如方法返回一个String,则为String.class
                Class returnType = ms[i].getReturnType();
                //获得类类型的不带包名的名字,getName()则为带包名的名字
                System.out.print(returnType.getSimpleName() + "  ");
                //得到方法的名称
                System.out.print(ms[i].getName() + " (");
                //获取参数类型的类类型
                Class[] paramTypes = ms[i].getParameterTypes();
                for (Class clazz : paramTypes) {
                    System.out.print(clazz.getSimpleName() + " , ");
                }
                System.out.println(" )");
            }
        }
    
        //反射获取成员变量
        public static void printFiledMessage(Object obj) {
            //获取字节码,或称类类型
            Class c = obj.getClass();
            System.out.println("类的名称为:" + c.getName());//c.getSimpleName()则不带包名
    
            /**
             * 成员变量也是对象,万物皆对象
             * getFields()获取所有public的成员变量信息,包括父类的
             * getDeclaredFields()获取自己声明的所有权限的成员变量信息
             */
            Field[] fs = c.getDeclaredFields();
            for (Field field : fs) {
                //获得成员变量的类型的类类型
                Class fieldType = field.getType();
                //获得成员变量类型的不带包名的名称
                String typeName = fieldType.getSimpleName();
                //获得成员变量的名称
                String fieldName = field.getName();
                System.out.println(typeName + " " + fieldName);
            }
        }
    
        //反射获取成员构造函数
        public static void printConstructorMessage(Object obj) {
            //获取字节码,或称类类型
            Class c = obj.getClass();
            System.out.println("类的名称为:" + c.getName());//c.getSimpleName()则不带包名
    
            /**
             * 构造函数也是对象,万物皆对象!
             * getConstructors获取所有public的构造函数,包括父类的
             * getDeclaredConstructors()获取自己声明的所有权限的构造函数,不包父类的
             */
            Constructor[] cs = c.getDeclaredConstructors();
            for (Constructor constructor : cs) {
                System.out.print(constructor.getName() + " (");
                //获取构造函数的参数列表
                Class[] paramTypes = constructor.getParameterTypes();
                for (Class clazz : paramTypes) {
                    System.out.print(clazz.getSimpleName() + " ,");
                }
                System.out.println(" )");
            }
        }
    
        //方法的反射调用
        public static void printMethodInvoke() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            Foo foo = new Foo();
            //要获取一个类的方法,先要获取类类型(或称字节码)
            Class c = foo.getClass();
            /**
             * getMethod()获取的是所有public方法,包父类的
             * getDeclaredMethod()获取自己声明的所有权限方法,不包父类的
             */
            Method method = c.getDeclaredMethod("print", int.class, int.class);
            //方法的反射调用 用Method对象来进行调用
            //如果方法没有返回值返回null,否则返回具体的返回值
            Object o = method.invoke(foo, 10, 20);
        }
    
        //通过反射验证泛型擦除
        public static void printFanXingClear() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            ArrayList<String> list = new ArrayList<>();
            list.add("你好");
            /**
             * list.add(45);是不是会出错?
             * 但是!泛型是防止错误输入的,编译后泛型擦除,不存在泛型
             * 下面在运行时通过反射证明
             */
             Class clazz = list.getClass();
    
             Method method = clazz.getMethod("add",Object.class);
             method.invoke(list,new Integer(45));
    
            System.out.println(list);
        }
    }
  • 相关阅读:
    Git 9. 远程仓库
    Git 8. 删除文件
    Git 7. 撤销修改
    # 并发编程 -进程理论-进程的方法
    socket 上传 -- 异常处理--UDP协议 --自定义socket #29
    socket(套接字)
    面向过程补充 网络编程 #27
    ATM
    选课系统 -- # 25 -26
    面向对象高级 1.反射 2.元类 # 24
  • 原文地址:https://www.cnblogs.com/liclBlog/p/15349537.html
Copyright © 2020-2023  润新知