• Java反射


    1.反射机制是什么?

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

    2.反射机制能做什么?

    • 获得类的定义信息
      • 包名、类名
      • 成员变量定义信息
      • 构造方法定义信息
      • 方法定义信息
    • 在运行时创建对象
    • 在运行时调用成员

    3.反射应用场景

    • 框架中对象的构建(例如mybatis中的resultType,resultMap,spring中的bean)

    • 框架中方法的调用(例如对象set方法,get方法,spring mvc 控制层方法,..)

      总之:反射不能预知未来,但可驾驭未来,通过反射可以更好构建一些编程框架,
      以实现通用性编程,从而达到简化代码编写。

    4.反射机制API

    4.1 获取Class对象(字节码对象):可理解为反射应用的入口

    • 类名.class
    • Class.forName("包名.类名")
    • 实例对象.getClass()
    数组对象是通过 实例对象.getClass().getComponentType()
    说明:返回数组中元素的Class对象,如果不是Class对象那么返回null
          非数组类型不能通过**getComponentType()**方法获得元素的Class对象类型
    

    Class<?> java.lang.Class.getComponentType()

    4.2 获取包名类名(c为Class对象实例)

    • c.getPackage.getName() 包名
    • c.getName() 完整类名
    • c.getSimpleName() 简写类名

    4.3 成员变量的定义信息

    • getFields()
      获得所有可见的变量,包含从父类继承的变量

    • getDeclaredFields()
      获得本类定义的变量,包括私有,不包含继承的变量

    • getField(变量名)

    • getDeclaredField(变量名)

    4.4 构造方法的定义信息

    • getConstructors()
      获得所有可见的构造方法

    • getDeclaredConstructors()
      获得所有构造方法,包括私有

    • getConstructor(参数类型列表)

    • getDeclaredConstructor(参数类型列表)

    4.5 方法的定义信息

    • getMethods()
      获得所有可见的方法,包含从父类继承的方法

    • getDeclaredMethods()
      获得所有本类定义的方法,包括私有,不包含继承的方法

    • getMethod(方法名,参数类型列表)

    • getDeclaredMethod(方法名,参数类型列表)

    4.6 反射创建对象

    • 执行无参构造
      Object obj = c.newInstance()

    • 执行有参构造

      1. 获得构造方法
        Constructor t = c.getDeclaredConstructor(int.class, String.class);

      2. 创建对象,并执行这个构造方法
        Object obj = t.newInstrance(5, "sdfsd");

    4.7 反射调用成员变量

    • Field f = c.getDeclaredField("name"); 获取变量

    • f.setAccessible(true) 使私有变量,也能被访问

    • f.set(对象, "张三"); 为变量赋值

      第一个参数,指定对象,为指定对象的变量赋值
      静态变量,第一个参数给 null

    • f.get(对象) 访问变量的值

    4.8 反射调用方法

    • 获取方法
      Method t = c.getDeclaredMethod("f1",int.class,String.class);

    • 使私有方法可以被调用
      t.setAccessible(true);

    • 反射调用方法
      Object r = t.invoke(对象, 5, "abc")

      静态方法,第一个参数给 null
      如果没有返回值,得到 null

    5. 反射应用实例

    5.1 在泛型为Integer的ArrayList中存放一个String类型的对象

    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    /**
     * ClassName: Test1
     * Function:  在泛型为Integer的ArrayList中存放一个String类型的对象
     * date:     2020/01/20
     * author     Luzy
     * version    V1.0
     */
    public class Test1 {
        public static void main(String[] args) throws Exception {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(123);
            list.add(520);
            Method method = list.getClass().getMethod("add", Object.class);
            method.invoke(list, "Java反射机制实例");
            System.out.println(list.toString());
    
        }
    }
    
    

    输出结果:

    [123, 520, Java反射机制实例]

    5.2 通过反射取得并修改数组的信息

    import java.lang.reflect.Array;
    import java.lang.reflect.Field;
    import java.util.Arrays;
    
    /**
     * ClassName: Test2
     * Function:  通过反射修改String
     * date:     2020/01/20
     * author     Luzy
     * version    V1.0
     */
    public class Test2 {
        public static void main(String[] args) throws Exception {
            String str = new String("恭喜发财!");//
            System.out.println("输出原本str的内容:" + str);
            //1、获取String类对应的Class
            Class<? extends String> clazz = str.getClass();
            //2、通过clazz获取类中的value属性
            Field value = clazz.getDeclaredField("value");
            //3、需要设置私有属性可以被操作后才能操作属性值
            value.setAccessible(true);
            //4、获取value属性里面的值(内存地址)
            //由于 String里面的值是存放在char[] 数组里面的,所以需要用一个char[]接收
            char[] temp = (char[])value.get(str);
            //5、通过temp的地址引用 找到真实String对象中的数组,修改数组内的每一个元素
            //由于此处是char类型,所以要用单引号
            temp[0] = '新';
            temp[1] = '年';
            temp[2] = '快';
            temp[3] = '乐';
            System.out.println("反射操作过后的str内容:"+str);
        }
    }
    
    
    

    输出结果:

    输出原本str的内容:恭喜发财!
    反射操作过后的str内容:新年快乐!

    5.3 反射机制应用于工厂模式

    /**
     * ClassName: Test3
     * Function:  反射机制应用于工厂模式
     * date:     2020/01/20
     * author     Luzy
     * version    V1.0
     */
    interface Fruit {
        public abstract void eat();
    }
    class Apple implements Fruit {
        public void eat() {
            System.out.println("Apple");
        }
    }
    class Orange implements Fruit {
        public void eat() {
            System.out.println("Orange");
        }
    }
    class Factory {
        public static Fruit getInstance(String ClassName) {
            Fruit f = null;
            try {
                f = (Fruit) Class.forName(ClassName).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return f;
        }
    }
    /**
     * 对于普通的工厂模式当我们在添加一个子类的时候,就需要对应的修改工厂类。 当我们添加很多的子类的时候,会很麻烦。
     *
     * 现在我们利用反射机制实现工厂模式,可以在不修改工厂类的情况下添加任意多个子类。
     *
     * 但是有一点仍然很麻烦,就是需要知道完整的包名和类名,这里可以使用properties配置文件来完成。
     *
     * java 读取 properties 配置文件 的方法可以自行百度
     *
     *
     */
    public class Test3 {
        public static void main(String[] args) throws Exception {
            Fruit f = Factory.getInstance("Apple");
            if (f != null) {
                f.eat();
            }
        }
    }
    

    输出结果:

    Apple

  • 相关阅读:
    PHP异常与错误处理机制
    工作中图片上传遇到的一个问题
    PHP遍历目录四种方法
    ssh框架中.xml文件小技巧分离xml
    读取XML文件内容
    spring_AOP
    spring_AOP_XML
    spring_AOP_annotation
    js异步刷新局部页面
    HQL count(*)
  • 原文地址:https://www.cnblogs.com/sanye613/p/13298121.html
Copyright © 2020-2023  润新知