菜鸟之路Day22一一反射与动态代理

简介: 本文介绍了Java反射机制和动态代理的基本概念及应用。反射允许编程访问类的成员变量、构造方法和成员方法,通过三种方式获取Class对象,并演示了如何使用反射创建对象、调用方法和修改字段值。动态代理则通过接口实现无侵入式功能增强,展示了如何利用`Proxy`类和`InvocationHandler`接口生成代理对象并拦截方法调用。结合实例代码,详细讲解了反射在实际开发中的应用场景,如保存对象信息到文件和根据配置文件动态创建对象。反射的主要作用包括:1. 获取类的所有信息。2. 结合配置文件动态创建对象。动态代理的核心优势在于能够在不修改原有代码的情况下,为对象添加额外功能。

菜鸟之路Day22一一反射与动态代理

作者:blue

时间:2025.3.4

0.概述

内容学习自黑马程序员BV1yW4y1Y7Ms

1.什么是反射

反射允许对成员变量,成员方法和构造方法的信息进行编程访问

获取class对象 Class

构造方法 Constructor

字段(成员变量)Field

成员方法 Method

2.获取class对象的三种方式

public class myreflectDemo1 {
   
    public static void main(String[] args) throws ClassNotFoundException {
   
        /*
        * 获取class对象的三种方式
        * 1.Class.forName("全类名");
        * 2.类名.class;
        * 3.对象.getClass();
        * */
        //1.第一种方式
        //全类名:包名+类名
        //最为常用的
        Class clazz1 = Class.forName("myreflect.Student");

        //2.第二种方式
        //一般更多的是当做参数进行传递
        Class clazz2 = Student.class;

        //3.第三种方式
        //当我们已经有这个类的对象时,才可以使用
        Student s = new Student();
        Class clazz3 = s.getClass();

        System.out.println(clazz1 == clazz2);
        System.out.println(clazz2 == clazz3);
    }
}
AI 代码解读

3.反射获取构造方法

类中有四个构造方法

    public Student() {
   
    }

    public Student(String name){
   
        this.name = name;
    }

    protected Student(int age){
   
        this.age = age;
    }

    private Student(String name, int age) {
   
        this.name = name;
        this.age = age;
    }
AI 代码解读

对获取构造方法相关方法的实例

public class myReflectDemo2 {
   
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
   
        /*
        * Class类中用于获取构造方法的方法
        * Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
        * Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
        * Constructor<?>getConstructor(Class<?>...parameterTypes):返回单个公共构造方法对象
        * Constructor<?>getDeclaredConstructor(Class<?>...parameterTypes):返回单个构造方法对象
        *
        * Constructor类中用于创建对象的方法
        * T newInstance(Object... initargs):根据指定的构造方法创建对象
        * setAccessible(boolean flag):设置为true,表示取消访问检查
        * */

        //获取Class对象(Student类)
        Class clazz = Class.forName("myreflect.Student");

        /*
        //返回所有公共构造方法对象的数组
        Constructor[] cons1 = clazz.getConstructors();
        for (Constructor constructor : cons1) {
            System.out.println(cons1);
        }
        */


        /*
        //返回所有构造方法对象的数组
        Constructor[] cons2 = clazz.getDeclaredConstructors();
        for (Constructor constructor : cons2) {
            System.out.println(constructor);
        }
        */

        //获取一个公共的空参构造
        Constructor con1 = clazz.getConstructor();
        System.out.println(con1);

        //获取一个公共的参数为String的构造
        Constructor con2 = clazz.getConstructor(String.class);
        System.out.println(con2);

        //获取一个私有的,带两个参数的构造
        Constructor con3 = clazz.getDeclaredConstructor(String.class,int.class);
        System.out.println(con3);

        //获取构造方法的修饰符的状态码
        int modifiers = con3.getModifiers();
        System.out.println(modifiers);//con3是private的所以他的状态码是2

        //获取构造方法的参数列表
        Parameter[] parameters = con3.getParameters();
        for (Parameter parameter : parameters) {
   
            System.out.println(parameter);
        }

        //利用获取到的Class对象,来创建其对应的对象
        //调用方法newInstance
        //但是这里展现出反射的一个用法
        //就是暴力反射
        //可以临时取消权限校验,使用本来被私有化的构造方法来创建对象

        con3.setAccessible(true);//临时取消权限校验
        Student s = (Student) con3.newInstance("张三",18);
        System.out.println(s);
    }
}
AI 代码解读

4.反射获取成员变量

private String name;
private int age;
public String gender;
//总共有三个成员变量
AI 代码解读

对获取成员变量相关方法的实例

public class Test {
   
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
   
        /*
        * Class类中用于获取成员变量的方法
        * Field[] getFields():返回所有公共成员变量对象的数组
        * Field[] getDeclaredFields():返回所有成员变量的数组
        * Field getField(String name):返回单个公共成员变量对象
        * Field getDeclaredField(String name):返回单个成员变量对象
        *
        * Field类中用于创建对象的方法
        * void set(Object obj,Object value):赋值
        * Object get(Object obj)获取值
        * */

        //获取Class(Student)对象
        Class<?> clazz = Class.forName("myreflect.myreflectDemo3.Student");

        //返回所有公共成员变量对象的数组
        Field[] fields1 = clazz.getFields();
        /*for (Field field : fields1) {
            System.out.println(field);
        }*/

        //返回所有成员变量的数组
        Field[] fields2 = clazz.getDeclaredFields();
        /*for (Field field : fields2) {
            System.out.println(field);
        }*/

        //返回单个 公共 成员变量对象
        Field field = clazz.getField("gender");
        //System.out.println(field);

        //返回单个成员变量对象
        Field field1 = clazz.getDeclaredField("name");
        //System.out.println(field1);

        //获取变量的权限修饰符
        int modifiers = field1.getModifiers();
        //System.out.println(modifiers);

        //获取成员变量的数据类型
        Class<?> type = field1.getType();
        //System.out.println(type);

        //获取或修改成员变量中的值
        //可以通过暴力反射直接获取或修改
        Student s = new Student("zhangsan",23,"男");
        field1.setAccessible(true);////临时取消该变量的权限校验
        String value = (String)field1.get(s);
        System.out.println(value);

        field1.set(s,"lisi");
        System.out.println(s);
    }
}
AI 代码解读

5.反射获取成员方法

类中有两个成员方法

     private String eat(String something){
   
        System.out.println("正在吃"+something);
        return "nice";
    }

    //一个重载
    public void eat(String something,int count) throws IOException,NullPointerException {
   
        System.out.println("正在吃"+count+"个"+something);
    }
AI 代码解读

对获取成员方法的实例

public class Test4 {
   
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
   
        /*
        * Class类中用于获取成员方法的方法
        * Method[] getMethods():返回所有公共成员方法对象数组,包括继承的
        * Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
        * Method getMethod(String name,Class<?>...parameterTypes):返回单个公共成员方法对象
        * Method getDeclaredMethod(String name,Class<?>...parameterTypes):返回单个成员方法对象
        * */

        Class clazz = Class.forName("myreflect.myreflectDemo4.Student");

        //返回所有公共成员方法对象数组,包括继承的
        Method[] methods = clazz.getMethods();
        /*for (Method method : methods) {
            System.out.println(method);
        }*/

        //返回所有成员方法对象的数组,不包括继承的
        Method[] methods1 = clazz.getDeclaredMethods();
        /*for (Method method : methods1) {
            System.out.println(method);
        }*/

        //返回单个 公共 成员方法对象
        Method eat = clazz.getMethod("eat", String.class, int.class);
        //System.out.println(eat);

        //返回单个成员方法对象
        Method eat_private = clazz.getDeclaredMethod("eat", String.class);
        //System.out.println(eat_private);

        //获取方法的修饰符
        int modifiers = eat_private.getModifiers();
        //System.out.println(modifiers);

        //获取方法的名字
        //System.out.println(eat_private.getName());

        //获取方法的形参
        Parameter[] parameters = eat_private.getParameters();
        /*for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }*/

        //获取方法抛出的异常
        Class<?>[] exceptionTypes = eat.getExceptionTypes();
        for (Class<?> exceptionType : exceptionTypes) {
   
            System.out.println(exceptionType);
        }

        /*
        * Method类中用于创建对象的方法
        *   Object invoke(Object obj,Object... args):运行方法
        *   参数一:用obj对象调用该方法
        *   参数二:调用方法的传递的参数(如果没有就不写)
        *   返回值:方法的返回值(如果没有就不写)
        * */

        Student stu = new Student("zhangsan",14,"男");
        //暴力反射调用私有化方法
        eat_private.setAccessible(true);
        Object x = eat_private.invoke(stu, "牛肉");
        System.out.println(x);
    }
}
AI 代码解读

6.综合练习

反射的作用

①获取一个类里面所有的信息,获取到了之后,再执行其他业务逻辑

②结合配置文件,动态的创建对象并调用方法

6.1保存信息

对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去

public class Test {
   
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, IOException {
   
        Student stu = new Student("zhangsan",18,"男");
        Teacher t = new Teacher("lisi","10000");

        saveObject(t);

    }

    private static void saveObject(Object object) throws ClassNotFoundException, IllegalAccessException, IOException {
   
        //获取Class对象
        Class clazz = object.getClass();

        //获取所有成员变量
        Field[] declaredFields = clazz.getDeclaredFields();
        BufferedWriter bw = new BufferedWriter(new FileWriter("src\\MyReflectTest\\TestOne\\a.txt"));

        //遍历
        for (Field declaredField : declaredFields) {
   
            //暴力反射
            declaredField.setAccessible(true);
            //获取变量名与值
            String name = declaredField.getName();
            Object o = declaredField.get(object);
            //写出数据
            bw.write(name+"="+o);
            bw.newLine();
        }

        //释放资源
        bw.close();
    }
}
AI 代码解读

6.2跟配置文件结合动态创建

public class Test {
   
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
   
        //1.获取配置文件中的信息
        Properties properties = new Properties();
        FileInputStream fis = new FileInputStream("src/MyReflectTest/TestTwo/a.properties");
        properties.load(fis);
        fis.close();
        //System.out.println(properties);

        //2.获取全类名和方法名
        String className = (String)properties.get("className");
        String Method = (String)properties.get("Method");

        //3.利用反射创建对象并运行方法
        Class clazz = Class.forName(className);

        //获取构造方法
        Constructor declaredConstructor = clazz.getDeclaredConstructor();
        //创建对象
        Object o = declaredConstructor.newInstance();

        //获取成员方法并运行
        java.lang.reflect.Method declaredMethod = clazz.getDeclaredMethod(Method);
        declaredMethod.setAccessible(true);
        declaredMethod.invoke(o);
    }
}
AI 代码解读

6.3总结

1.反射的作用

​ ①获取任意一个类中的所有信息

​ ②结合配置文件动态创建对象

2.获得class字节码文件对象的三种方式

​ ①Class.forName("全类名")

​ ②类名.class

​ ③对象.getclass();

3.如何获取构造方法,成员方法,成员变量

​ get:获取 set:设置

​ Constructor:构造方法 Parameter:参数

​ Field:成员变量 Modifiers:修饰符

​ Method:方法 Declared:私有的

7.动态代理

1.为什么需要代理?

代理可以无侵入式的给对象增强其他的功能

调用者 -> 代理 -> 对象

2.代理长什么样子?

代理里面就是对象要被代理的方法

3.Java通过什么来保证代理的样子?

通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法

Star接口

public interface Star {
   

    public abstract String sing(String Singname);

    public abstract void dance();
}
AI 代码解读

BigStar类

public class BigStar implements Star{
   

    private String name;

    public BigStar() {
   
    }

    public BigStar(String name) {
   
        this.name = name;
    }

    @Override
    public String sing(String Singname) {
   
        System.out.println(this.name+"正在唱"+Singname);
        return "谢谢";
    }

    @Override
    public void dance() {
   
        System.out.println(this.name+"正在跳舞");
    }

    public String getName() {
   
        return name;
    }

    public void setName(String name) {
   
        this.name = name;
    }
}
AI 代码解读

代理

public class ProxyUtil {
   
    public static Star createProxy(BigStar bigStar){
   
        /*
        * java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法
        * public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
        * 参数一:用于指定用哪个类加载器,去加载生成的代理类
        * 参数二:指定接口,这些接口用于指定生成的代理长什么样子,也就是有哪些方法
        * 参数三:用来指定生成的代理对象要干什么事情
        * */
        Star star = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),//参数一:用于指定用哪个类加载器,去加载生成的代理类
                new Class[]{
   Star.class},//参数二:指定接口,这些接口用于指定生成的代理长什么样子,也就是有哪些方法
                new InvocationHandler() {
   
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
                         /*
                         * 参数一:代理的对象
                         * 参数二:要运行的方法 sing
                         * 参数三:调用sing方法时,传递的实参
                         * */
                        if("sing".equals(method.getName())){
   
                            System.out.println("准备话筒,收钱");
                        }else if("dance".equals(method.getName())){
   
                            System.out.println("准备场地,收钱");
                        }
                        //让bigStar执行相关方法
                        //依靠反射实现
                        return method.invoke(bigStar,args);
                    }
                }
        );
        return star;
    }
}
AI 代码解读

测试类

public class Test {
   
    public static void main(String[] args) {
   
        //获取代理对象
        BigStar star = new BigStar("鸡哥");
        Star proxy = ProxyUtil.createProxy(star);

        //调用唱歌方法
        String s = proxy.sing("只因你太美");
        System.out.println(s);
    }
}
AI 代码解读
目录
打赏
0
0
0
0
153
分享
相关文章
|
10月前
|
C++的学习之路:21、继承(2)
C++的学习之路:21、继承(2)
40 0
菜鸟之路Day13一一方法引用
### 菜鸟之路Day13——方法引用 作者:blue 日期:2025.1.31 本文介绍了Java中的方法引用,它是对Stream流的优化,简化了代码结构。方法引用可以用于静态方法、成员方法和构造方法。通过将已有方法作为函数式接口的实现,减少了匿名内部类和Lambda表达式的冗余。文中通过多个实例演示了方法引用的应用场景,包括倒序排序、字符串转换、集合过滤及对象构造等操作,帮助读者更好地理解和使用这一特性。
61 17
c++的学习之路:20、继承(1)
c++的学习之路:20、继承(1)
73 0
|
9月前
|
Java 面向对象编程:父类与子类的“传承”与“创新”之路
【6月更文挑战第16天】Java 中的父类与子类展示了面向对象的“传承”与“创新”。子类`Dog`继承`Animal`,获取其属性和方法如`name`和`makeSound`。子类通过`@Override`增强`makeSound`,显示多态性。设计父类时应考虑普遍性,子类创新专注自身特性,遵循继承最佳实践,利用复用提升效率,构建可维护的软件系统。
189 57
技术成神之路:设计模式(一)单例模式
【7月更文挑战第3天】技术成神之路:设计模式(一)单例模式
56 1
从 Java 小白到大神:一文带你搞懂子类如何“继承”父类江山,开创新世界!
【6月更文挑战第16天】Java中的继承是面向对象的核心,它允许子类继承父类的属性和方法,提高代码复用。通过实例,如`Animal`和`Dog`类,显示了如何创建和覆盖方法。继承不仅简化代码,还支持多态性,是构建可扩展系统的关键。从新手到专家,掌握继承意味着掌握编程的强大工具,能解锁更复杂的系统设计和优化。
173 3
【面试问题】动态代理是什么?
【1月更文挑战第27天】【面试问题】动态代理是什么?
Java动态代理:一个面包店的动态代理帝国
Java动态代理:一个面包店的动态代理帝国
128 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等