• 滴水穿石-11 反射


    1 反射中涉及的几个概念

    1.1 类的加载

      当程序要使用某个类的时候,如果这个类尚未加载到内存中,系统会通过加载,连接,初始化三步实现对该类的初始化.

    1.2 类的初始化时机 

        创建类的实例;
    
      访问类的静态成员;(为静态变量赋值;调用静态方法)
    
      使用反射强制创年某个类或接口对应的java.lang.Class对象
    
      初始化某个类的子类
    
      直接使用java.exe命令运行某个主类
    类的初始化时机

    1.3 反射

      在运行状态中,获取类的成员的机制.(类的成员:所有的属性和方法)

      首先获取Class类(字节码文件) 

    Class类:
            成员变量    Field
            构造方法    Constructor
            成员方法    Method
    Class类
    package d11;
    
    //获取Class文件对象的三种方式
    //A:Object类的getClass()方法
    //B:数据类型的静态属性Class
    //C:Class类中的静态方法(className 注意:是类的全路径:d11.Person)
    //    public static Class forName(String className)
    public class ReflectDemo1 {
        public static void main(String[] args) throws ClassNotFoundException {
            Person p = new Person();
            //A:Object类的getClass()方法
            Class c1 = p.getClass();
             
            //B:数据类型的静态属性Class
            Class c2 = Person.class;
             
            //C:Class类中的静态方法(className 注意:是类的全路径:d11.Person)
            Class c3 =Class.forName("d11.Person") ;
            
            System.out.println(c1+" "+c2+" "+c3);
            
            //输出结果 class d11.Person class d11.Person class d11.Person
    
        }
    }
    获取Class类的三种方法

    2  反射练习

    2.1 获取构造方法

    package d11;
    
    public class Person {
    
        // 定义三种不同访问类型的构造方法
        public Person() {
        }
    
        Person(String name) {
            this.name = name;
        }
    
        private Person(String name, int age, String address) {
            this.name = name;
            this.age = age;
            this.address = address;
        }
    
        // 定义三种不同访问类型的成员变量
        public String name;
        int age;
        private String address;
        // 定义三种不同访问类型的成员方法
        public void show() {
            System.out.println("show");
        }
        void show(String msg) {
            System.out.println("show: "+msg);
        }
        private String show(String name,int age,String address) {
            return "姓名 : "+name+" 年龄: "+age+" 地址: "+address;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + ", address=" + address + "]";
        }
        
         
    }
    Person
    package d11;
    
    import java.lang.reflect.Constructor;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo2_GetConstructor {
        public static void main(String[] args) throws ClassNotFoundException {
            // 创建Class对象
            Class c1 = Class.forName("d11.Person");
            // 获取所有的public构造方法
            Constructor[] cs = c1.getConstructors();
            for (Constructor constructor : cs) {
                System.out.println(constructor);
            }
            /*
             * 输出结果 public d11.Person() 分析:只有Public权限的输出
             */
            
            // 获取所有的构造方法
            Constructor[] cs2 = c1.getDeclaredConstructors();
            for (Constructor constructor : cs2) {
                System.out.println(constructor);
            }
            /*
             * private d11.Person(java.lang.String,int,java.lang.String)
               d11.Person(java.lang.String)
               public d11.Person()         
             */
            // 获取所有的构造方法(貌似还有一个排序)
            
            
        }
    }
    获取所有的构造方法

    2.1.1 public权限构造方法的获取和使用

    package d11;
    
    import java.lang.reflect.Constructor;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo3_GetConstructor_public {
        public static void main(String[] args) throws Exception  {
            //01-创建Class对象
            Class c1 = Class.forName("d11.Person");
            //02-获取所有的public构造方法
            Constructor  cpub = c1.getConstructor();
            //03-通过构造方法创建新对象 
            Object obj = cpub.newInstance();
            System.out.println(obj.toString());
            /*输出结果
             * Person [name=null, age=0, address=null]
             * */
        }
    }
    View Code

    2.1.2 protect权限构造方法的获取和使用

    package d11;
    
    import java.lang.reflect.Constructor;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo3_GetConstructor_protect {
        public static void main(String[] args) throws Exception  {
            //01-创建Class对象
            Class c1 = Class.forName("d11.Person");
            //02-获取Protect构造方法 (含有参数)
            Constructor  cpub = c1.getDeclaredConstructor(String.class);         
            //03-通过构造方法创建新对象 
            Object obj = cpub.newInstance("张三");
            System.out.println(obj.toString());
            /*输出结果
             * Person [name=张三, age=0, address=null]
             * */
        }
    }
    Protect

    2.1.3 private权限构造方法的获取和使用

    package d11;
    
    import java.lang.reflect.Constructor;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo3_GetConstructor_private {
        public static void main(String[] args) throws Exception  {
            //01-创建Class对象
            Class c1 = Class.forName("d11.Person");
            //02-获取Protect构造方法 (含有参数)
            Constructor  cpub = c1.getDeclaredConstructor(String.class,int.class,String.class);
            //03-设置访问权限
            cpub.setAccessible(true);
            //04-通过构造方法创建新对象 
            Object obj = cpub.newInstance("张三",10,"中国");
            System.out.println(obj.toString());
            /*输出结果
             * Person [name=张三, age=10, address=中国]
             * */
        }
    }
    private

    2.2 获取成员变量

    package d11;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Field;
    
    //通过Class对象获取所有的成员变量,得到一个数组集合
    
    public class ReflectDemo2_GetFields {
        public static void main(String[] args) throws ClassNotFoundException {
            // 创建Class对象
            Class c1 = Class.forName("d11.Person");
            // 获取所有的public成员变量
            Field[] cs = c1.getFields();
            for (Field field : cs) {
                System.out.println(field);
            }
            /*
             * 输出结果 public java.lang.String d11.Person.name 分析:只有Public权限的输出
             */
            
            // 获取所有的成员变量
            Field[] cs2 = c1.getDeclaredFields();
            for (Field field : cs2) {
                System.out.println(field);
            }
            /*
             * public java.lang.String d11.Person.name
                int d11.Person.age
                private java.lang.String d11.Person.address         
             */
            // 获取所有的成员变量(貌似还有一个排序)
            
            
        }
    }
    ReflectDemo2_GetFields

    2.2.1 public权限成员变量的获取和使用

    package d11;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo3_GetField_public {
        public static void main(String[] args) throws Exception  {
            //01-创建Class对象
            Class c1 = Class.forName("d11.Person");
            Constructor  cpub = c1.getConstructor();         
            //03-通过构造方法创建新对象 
            Object obj = cpub.newInstance();
            
            //04-获取成员变量
            Field fName = c1.getField("name");
            //05-设置
            fName.set(obj, "李四");
            System.out.println(obj.toString());
        }
    }
    ReflectDemo3_GetField_public

    2.2.2 protect权限成员变量的获取和使用

    package d11;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo3_GetField_protect {
        public static void main(String[] args) throws Exception  {
            //01-创建Class对象
            Class c1 = Class.forName("d11.Person");
            //02-获取Protect构造方法 (含有参数)
            Constructor  cpub = c1.getConstructor();         
            //03-通过构造方法创建新对象 
            Object obj = cpub.newInstance();
            //04 获取age
            Field fAge = c1.getDeclaredField("age");
            fAge.set(obj, 20);
            System.out.println(obj.toString());
            /*输出结果
             * Person [name=null, age=20, address=null]
             * */
        }
    }
    ReflectDemo3_GetField_protect

    2.2.3 private权限成员变量的获取和使用

    package d11;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo3_GetField_private {
        public static void main(String[] args) throws Exception  {
            //01-创建Class对象
            Class c1 = Class.forName("d11.Person");
            //02-获取Protect构造方法 (含有参数)
            Constructor  cpub = c1.getConstructor();
            
            //03-通过构造方法创建新对象 
            Object obj = cpub.newInstance();
            //04-获取Field
            Field fAddress = c1.getDeclaredField("address");
            fAddress.setAccessible(true);
            
            //03-设置访问权限
            fAddress.set(obj, "中国");                
            System.out.println(obj.toString());
            /*输出结果
             * Person [name=null, age=0, address=中国]
             * */
        }
    }
    ReflectDemo3_GetField_private

     2.3 获取成员方法

    package d11;
    
    import java.lang.reflect.Method;
    import java.lang.reflect.Method;
    
    //通过Class对象获取所有的成员变量,得到一个数组集合
    
    public class ReflectDemo2_GetMethods {
        public static void main(String[] args) throws ClassNotFoundException {
            // 创建Class对象
            Class c1 = Class.forName("d11.Person");
            // 获取所有的public成员变量
            Method[] cs = c1.getMethods();
            for (Method method : cs) {
                //System.out.println(method);
            }
            /*
             * 输出结果 
    public java.lang.String d11.Person.toString()
    public void d11.Person.show()
    public final void java.lang.Object.wait() throws java.lang.InterruptedException
    public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
    public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
    public boolean java.lang.Object.equals(java.lang.Object)
    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()
    
             */
            
            // 获取所有的成员变量
            Method[] cs2 = c1.getDeclaredMethods();
            for (Method method : cs2) {
                System.out.println(method);
            }
            /*
    public java.lang.String d11.Person.toString()
    void d11.Person.show(java.lang.String)
    private java.lang.String d11.Person.show(java.lang.String,int,java.lang.String)
    public void d11.Person.show()
         
             */
            // 获取所有的成员变量(貌似还有一个排序)
            
            
        }
    }
    ReflectDemo2_GetMethods

     2.3.1 public权限成员方法的获取和使用

    package d11;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo3_GetMethod_public {
        public static void main(String[] args) throws Exception  {
            //01-创建Class对象
            Class c1 = Class.forName("d11.Person");
            Constructor  cpub = c1.getConstructor();         
            //03-通过构造方法创建新对象 
            Object obj = cpub.newInstance();
            
            //04-获取成员变量
            Method mshow = c1.getMethod("show");
            //05-设置
            mshow.invoke(obj);
            /*输出结果
             * show 
             * */
             
        }
    }
    ReflectDemo3_GetMethod_public

     2.3.2 protect权限成员方法的获取和使用

    package d11;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo3_GetMethod_protect {
        public static void main(String[] args) throws Exception  {
            //01-创建Class对象
            Class c1 = Class.forName("d11.Person");
            //02-获取Protect构造方法 (含有参数)
            Constructor  cpub = c1.getConstructor();         
            //03-通过构造方法创建新对象 
            Object obj = cpub.newInstance();
            //04 获取age
            Method mShow = c1.getDeclaredMethod("show",String.class);
            mShow.invoke(obj, "woshi Show");
            /*输出结果
             * show: woshi Show
             * */
        }
    }
    ReflectDemo3_GetMethod_protect

     2.3.3 private权限成员方法的获取和使用

    package d11;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    
    //通过Class对象获取所有的构造方法,得到一个数组集合
    
    public class ReflectDemo3_GetMethod_private {
        public static void main(String[] args) throws Exception  {
            //01-创建Class对象
            Class c1 = Class.forName("d11.Person");
            //02-获取Protect构造方法 (含有参数)
            Constructor  cpub = c1.getConstructor();
            
            //03-通过构造方法创建新对象 
            Object obj = cpub.newInstance();
            //04-获取Method
            Method mShow = c1.getDeclaredMethod("show",String.class,int.class,String.class);
            mShow.setAccessible(true);
            Object msg = mShow.invoke(obj, "zhang san",20,"China");
            String msgStr = (String)mShow.invoke(obj, "zhang san",20,"China");
            System.out.println(msg);
            System.out.println(msgStr);
            /*输出结果
             * 姓名 : zhang san 年龄: 20 地址: China
                姓名 : zhang san 年龄: 20 地址: China
    
             * */
        }
    }
    ReflectDemo3_GetMethod_private

     2.4 模拟配置文件完成方法调用

    2.4.1 假设有一个简单的配置文件

    2.4.2 有多个实体类文件

    package d11;
    
    public class Student {
    
        // 定义三种不同访问类型的构造方法
        public Student() {
        }
    
        Student(String name) {
            this.name = name;
        }
    
         
    
        // 定义三种不同访问类型的成员变量
        public String name;
         
        // 定义三种不同访问类型的成员方法
        public void show() {
            System.out.println("我是学生show方法!!");
        }
         
     
    }
    Student
    package d11;
    
    public class Person {
    
        // 定义三种不同访问类型的构造方法
        public Person() {
        }
    
        Person(String name) {
            this.name = name;
        }
    
        private Person(String name, int age, String address) {
            this.name = name;
            this.age = age;
            this.address = address;
        }
    
        // 定义三种不同访问类型的成员变量
        public String name;
        int age;
        private String address;
        // 定义三种不同访问类型的成员方法
        public void show() {
            System.out.println("show");
        }
        void show(String msg) {
            System.out.println("show: "+msg);
        }
        private String show(String name,int age,String address) {
            return "姓名 : "+name+" 年龄: "+age+" 地址: "+address;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + ", address=" + address + "]";
        }
        
         
    }
    Person

    2.4.3 创建一个测试类,完成多个类文件之间的调用

    package d11;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import java.util.Properties;
    
    public class Test {
    
        public static void main(String[] args) throws Exception {
            // 加载键值对数据
            Properties prop = new Properties();
            FileReader fr = new FileReader("D:\bbb\class.txt");
            prop.load(fr);
            fr.close();
            //获取数据
            String className = prop.getProperty("className");
            String methodName = prop.getProperty("methodName");
            //反射
            Class c = Class.forName(className);
            //调用构造方法
            Constructor con = c.getConstructor();
            Object obj = con.newInstance();
            //调用方法
            Method m = c.getMethod(methodName);
            m.invoke(obj);
            
        }
    
    }
    Test

    3 练习:

    3.1 向ArrayList<Integer>中添加一个字符串"hello"

    package d11;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    public class ArrayListDemo {
    
        public static void main(String[] args) throws Exception {
            //向ArrayList<Integer>中添加一个字符串"hello"
            ArrayList<Integer> array = new ArrayList<Integer>();
            Class c = array.getClass();
            Method m = c.getMethod("add", Object.class);
            m.invoke(array, "hello");
            m.invoke(array, "word");
            System.out.println(array);
            /*
             * [hello, word]
             * */
        }
    
    }
    ArrayListDemo

    3.2 添加一个工具类,给某个类中的某个属性复制

    package d11;
    
    import java.lang.reflect.Field;
    
    public class Tool {
        public void setProperty(Object obj,String PropertyName,Object value) throws Exception{
            //根据对象获取对象字节码文件
            Class c = obj.getClass();
            //根据c获取字段
            Field f = c.getDeclaredField(PropertyName);
            //给字段复制
            f.setAccessible(true);
            //给对象的成员变量赋值
            f.set(obj, value);                
        }
    }
    Tool
    package d11;
    
    public class ToolDemo {
        public static void main(String[] args) throws Exception {
            //给Person的Name赋值
            Person p = new Person();
            //注意此时不能给address 私有属性赋值
            Tool t = new Tool();
            t.setProperty(p, "address", "北京");
            
            System.out.println(p.toString());
            /*输出结果
             * Person [name=null, age=0, address=北京]
             * */
        }
    }
    ToolDemo

     4 动态代理

    现在有一个StudentDao接口和UserDao接口以及两个接口的实现类

    package d11;
    
    public interface StudentDao {
        public abstract void login();
        public abstract void register();
    }
    StudentDao
    package d11;
    
    public interface UserDao {
        public abstract void add();
        public abstract void modify();
        public abstract void find();
        public abstract void delete();
    }
    UserDao
    package d11;
    
    public class StudentDaoImp implements StudentDao {
    
        @Override
        public void login() {
            System.out.println("登录事件");
        }
    
        @Override
        public void register() {
            System.out.println("注册事件");
        }
    
    }
    StudentDaoImp
    package d11;
    
    public class UserDaoImp implements UserDao {
    
        @Override
        public void add() {
            System.out.println("添加事件");
        }
    
        @Override
        public void modify() {
            System.out.println("修改事件");
        }
    
        @Override
        public void find() {
            System.out.println("查询事件");
        }
    
        @Override
        public void delete() {
            System.out.println("删除事件");
        }
    
    }
    UserDaoImp

    一般的使用方式 

    package d11;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import java.util.Properties;
    
    public class TestDemo {
    
        public static void main(String[] args) throws Exception {
             StudentDaoImp s = new StudentDaoImp();
             s.login();
             s.register();
             /*输出结果
                  登录事件
                  注册事件 */
            //通过动态代理,需要创建一个动态代理对象
        }
    
    }
    TestDemo

    现在如果想在方法调用前加一个权限判断,以及在方法调用后做一个日志记录.而且相对User等类也添加同样的功能,可以通过动态代理实现.

    若实现动态代理,可借助Proxy类中的newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法

      若借助Proxy类中的newProxyInstance 需要一个参数InvocationHandler.所以县创建一个子类对象实现该接口

    package d11;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class MyInvocationHandler implements InvocationHandler {
    
        private Object target;
        public MyInvocationHandler(Object target) {
            this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            
            //重写invoke方法,需要一个目标 (添加一个构造方法)
            System.out.println("验证权限");
            Object result = method.invoke(target, args);
            System.out.println("日志记录");
            return result;
        }
    
    }
    MyInvocationHandler
    package d11;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Properties;
    
    public class TestDemo {
    
        public static void main(String[] args) throws Exception {
             StudentDaoImp s = new StudentDaoImp();
             s.login();
             s.register();
             /*输出结果
                  登录事件
                  注册事件 */
             System.out.println("---------");
             //若借助Proxy类中的newProxyInstance 需要一个参数InvocationHandler
             MyInvocationHandler handler = new MyInvocationHandler(s);
             StudentDao sp = (StudentDao)Proxy.newProxyInstance(s.getClass().getClassLoader(), s.getClass().getInterfaces(), handler);
             sp.login();
             sp.register();
             
             System.out.println("---------");
             //同理,调用其他的类
             UserDaoImp u = new  UserDaoImp();
             MyInvocationHandler handler2 = new  MyInvocationHandler(u);
             UserDao up = (UserDao)Proxy.newProxyInstance(u.getClass().getClassLoader(), u.getClass().getInterfaces(), handler2);
             up.add();
             
             
             /*输出结果
     登录事件
    注册事件
    ---------
    验证权限
    登录事件
    日志记录
    验证权限
    注册事件
    日志记录
    ---------
    验证权限
    添加事件
    日志记录
              */
        }
    
    }
    TestDemo
  • 相关阅读:
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-install-plugin:2.4: install (default-install) on project authorizationManagement-service: Failed to install metadata com.dmsdbj.itoo:autho
    IEDA中使用阿里插件Alibaba Cloud Toolkit和Arthas(阿尔萨斯)
    ECS与EDAS什么意思?
    【学习笔记】随机深林
    R概率分布函数使用小结
    KNN
    K-MEANS
    mac下安装face_recognition
    linux下配置face_recognition
    springboot-actuator
  • 原文地址:https://www.cnblogs.com/YK2012/p/8687359.html
Copyright © 2020-2023  润新知