[java学习日记]反射、动态代理

news2024/11/20 10:30:55

目录

一.反射的简单解释与获取字节码文件对象

二.获取构造方法对象Constructor

三.反射获取字节码文件中的成员变量Field

四.反射获取字节码文件中的成员方法:Method

五.反射练习:保存信息

六.反射练习:利用配置文件(存储类名和方法名),动态创建对象并调用方法

七.动态代理


一.反射的简单解释与获取字节码文件对象

反射:允许对封装类的成员变量、构造方法、成员方法获取出来然后进行操作,或者获取到如修饰符,名字等更加详细的信息
没有反射怎么拿?使用IO流!但是比较麻烦,这里就用反射咯
1.获取Class的有哪三种方式?
    1.Class.forName("全类名")
    2.类名.class
    3.对象.getClass()
对应三个不同的阶段
    1.源代码:编译时期
    2.加载阶段:在内存当中的时候
    3.运行阶段:已经有对象了
2.这三种方法获取的是什么对象?
public class Demo351 {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("(1)获取Class的第一种方式:需要传入全类名的字符串:包含包名,最为常用");
        System.out.println("IDEA中获取:选择类名,然后右键选择copy_Reference");
        Class<?> class1 = Class.forName("Day35_Reflect_DynamicAgent.Demo351");
        System.out.println(class1);

        System.out.println("(2)获取Class的第二种方式,通过类名调用");
        System.out.println("第二种则是多用于作为参数作为传递:比如当作锁");
        Class<?> class2 = Demo351.class;

        System.out.println("(3)获取Class的第三种方式,通过对象调用,也是获取的字节码文件");
        //已经有对象的时候才可以使用
        Class<?> class3 = new Student().getClass();

        System.out.print("2.前两个类对象都是获取的字节码文件,是同一个对象:");
        System.out.println(class2==class1);
    }
}

学生类JavaBean,下面案例都是使用的此学生类

//四个构造方法:两个是私有的
//有个成员方法抛出了异常
public class Student {
    private String name;
    private int age;
    public Student() {
    }

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

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

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) throws Exception{
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


二.获取构造方法对象Constructor

从字节码文件里面获取数据对象的内容:本类测试获取构造方法对象Constructor
1.使用什么方法获取所有公共构造方法呢?
2.使用什么方法获取所有构造方法呢(包括私有)?
3.获取单个构造方法时传入的参数应该是?
4.如何获取构造方法内的权限修饰符?
5.如何读取方法中的参数?
6.如何使用私有构造方法创建变量?
public class Demo352 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取字节码文件对象
        Class<?> studentClass = Class.forName("Day35_Reflect_DynamicAgent.Student");

        System.out.println("1.使getConstructors获取构造方法,获取所有公共构造方法");
        Constructor<?>[] constructors = studentClass.getConstructors();
        for (Constructor<?> constructor : constructors) System.out.println(constructor);

        System.out.println("2.获取所有构造方法(Declared:公开声明的)");
        constructors = studentClass.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) System.out.println(constructor);

        System.out.println("3.获取单个构造方法:指定构造方法可以传递参数:数据类型的字节码文件,基本数据类型也要传.class字节码文件");
        Constructor<?> constructor = studentClass.getConstructor();
        System.out.println(constructor);
        constructor = studentClass.getConstructor(String.class,int.class);
        System.out.println(constructor);
        constructor = studentClass.getDeclaredConstructor(int.class);
        System.out.println(constructor);

        //获取构造方法里面的内容
        System.out.println("4.使用getModifier方法读取权限修饰符:内容是2的整数倍(和底层运算效率有关,左右移就能改变)");
        //有什么用呢?写IDEA源码有用,提示能够直接看到能传上面参数
        System.out.println(constructor.getModifiers());

        System.out.println("5.使用getParameters方法读取有哪些参数");
        Parameter[] parameters = constructor.getParameters();
        for (Parameter parameter : parameters) System.out.println(parameter);

        System.out.println("6.使用构造方法创建对象:私有方法不能够创建对象,需要临时取消权限校验(暴力反射)");
        System.out.println("首先把构造方法调用setAccessible方法,传入true为参数");
        constructor.setAccessible(true);
        System.out.println("再使用构造方法的newInstance方法构造其对象");
        Student student = (Student) constructor.newInstance(23);
        System.out.println(student);
    }
}


三.反射获取字节码文件中的成员变量Field

反射获取字节码文件中的成员变量Field
1.获取单个变量需要传入的参数?
2.如何获取变量名?
3.如何获取变量类型?
4.如何获取对象中的变量的值?
5.如何修改对象中变量的值?
public class Demo353 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //获取Field也是一样的方法
        Class<?> studentClass = Class.forName("Day35_Reflect_DynamicAgent.Student");
        Field[] fields = studentClass.getDeclaredFields();
        for (Field field : fields) System.out.println(field);
        System.out.println("1.获取单个成员变量:传入变量名字符串");
        Field field = studentClass.getDeclaredField("age");
        //获取成员变量信息
        System.out.println(field.getModifiers());
        System.out.println("2.使用getName方法获取变量名");
        System.out.println(field.getName());
        System.out.println("3.使用getType方法获取变量类型");
        Class<?> type = field.getType();
        System.out.println(type);

        System.out.println("4.使用get方法传入某对象,获取这个成员变量在该对象中的值,同样也需要取消权限校验");
        field.setAccessible(true);
        Student student = new Student("zhangsan", 123);
        Object age = field.get(student);
        System.out.println(age);

        System.out.println("5.使用set方法,传入某对象与修改的值,对该对象中的成员变量修改");
        field.set(student,1234);
        System.out.println(student);
    }
}


四.反射获取字节码文件中的成员方法:Method

反射获取字节码文件中的成员方法:Method
1.使用getMethods方法与getDeclaredMethods方法有什么区别?
2.如何获取单个方法,传入的参数是?
3.如何返回方法抛出的异常?
4.如何使用method对某对象调用方法?传入的参数与返回的参数有什么特点?
public class Demo354 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<?> studentClass = Class.forName("Day35_Reflect_DynamicAgent.Student");
        Method[] methods = studentClass.getMethods();
        System.out.println("1.使用getMethods方法同时也有继承与Object中的方法");
        for (Method method : methods)System.out.println(method);

        methods = studentClass.getDeclaredMethods();
        System.out.println("获取所有方法的时候不会包含继承下来的方法");
        for (Method method : methods)System.out.println(method);

        System.out.println("2.通过名字和形参获取一个方法,可以不加形参");
        Method method = studentClass.getMethod("setName",String.class);
        System.out.println(method);

        //修饰符,名字,参数
        System.out.println(method.getModifiers());
        System.out.println(method.getName());
        for (Parameter parameter : method.getParameters())System.out.println(parameter);

        System.out.println("3.使用getExceptionTypes返回方法抛出的异常数组");
        System.out.println(Arrays.toString(method.getExceptionTypes()));

        System.out.println("4.调用invoke(调用)方法,第一个参数传入对象,第二个参数没有就不写,方法没有返回也可以不写");
        Student student = new Student();
        method.invoke(student,"zhangsan");
        System.out.println(student);
    }
}

 


五.反射练习:保存信息

对于任意一个对象:把对象所有信息保存到文件当中,对于不同的对象都可以如此操作
public class Demo355 {
    final static String FILE_STR = "D:\\IDEACode\\demo1\\JAVA基础\\src\\Day35_Reflect_DynamicAgent\\message.properties";
    public static void main(String[] args) throws IllegalAccessException, IOException {
        Student student = new Student("zhansgan",123);
        Properties properties =new Properties();
        Class<?> studentClass = student.getClass();
        //获取字节码文件中的所有成员变量
        Field[] fields = studentClass.getDeclaredFields();
        for (Field field : fields) {
            //设置取消检验
            field.setAccessible(true);
            //获取变量名
            String name = field.getName();
            //获取对象中的该变量
            Object o = field.get(student);
            properties.put(name,o.toString());
        }
        properties.store(new FileWriter(FILE_STR),"addStudent");
    }
}


六.反射练习:利用配置文件(存储类名和方法名),动态创建对象并调用方法

public class Demo356 {
    final static String FILE_STR = "D:\\IDEACode\\demo1\\JAVA基础\\src\\Day35_Reflect_DynamicAgent\\prop.properties";
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Properties properties = new Properties();
        properties.load(new FileReader(FILE_STR));
        //获取字节码文件
        Class<?> aClass = Class.forName((properties.get("classname").toString()));
        //获取构造方法,创建对象
        Constructor<?> constructor = aClass.getConstructor();
        Object o = constructor.newInstance();
        //获取方法名并调用
        Method method = aClass.getMethod(properties.get("method").toString());
        System.out.println(method.invoke(o));
    }
}


七.动态代理

动态代理:不修改原有的代码,又需要增加额外功能
为了程序的健壮性,不改变原有代码的功能,使用动态代理完成一些额外的事情
想要找某个核心人物做事情,需要先找它的代理人去说要做的事情,代理人里面也要有核心任务的方法
如何确定需要代理的方法呢?
为了确定需要代理的方法,需要让核心人物与代理人都实现某一个接口

需要代理的类

public class BigStar implements Star {
    private String name;
    public BigStar() {}
    public BigStar(String name) {
        this.name = name;
    }

    @Override
    public String sing(String name){
        System.out.println(this.name+"正在唱:"+name);
        return "谢谢";
    }
    @Override
    public void dance(){
        System.out.println("跳舞");
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "BigStar{" +
                "name='" + name + '\'' +
                '}';
    }
}

需要代理的方法的接口

public interface Star {
    String sing(String name);
    void dance();
}

代理工具类 :用来创建代理对象

public class ProxyUtil {

    public static Star createProxy(BigStar bigStar) {
        System.out.println("""
                1.创建静态方法返回一个代理人(类型为BigStar实现的结构)
                方法作用:给明星对象创建一个代理
                形参:被代理的明星对象
                返回一个接口,也是返回代理对象
                """);
        System.out.println("2.使用Proxy的newProxyInstance方法创建代理人对象,传入三个参数");
        System.out.println("""
                参数一:指定类加载器加载生成的代理类:找到谁加载了这个类
                参数二:指定接口数组,用于指定代理能代理哪些方法
                参数三:指定代理要干什么事情,在这个参数需要的对象需要实现的方法参数有三个
                
                参数一:代理的对象,暂时用不到
                参数二:要运行的方法
                参数三:调用方法的时候需要传递的实参
                """);
        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 {
                        /*
                        参数一:代理的对象,暂时用不到
                        参数二:要运行的方法
                        参数三:调用方法的时候需要传递的实参
                        */
                        if ("sing".equals(method.getName()))
                            System.out.println("代理人:准备话筒");
                        else if ("dance".equals(method.getName()))
                            System.out.println("代理人:准备场地");
                        //返回运行结果
                        return method.invoke(bigStar, args);
                    }
                }
        );
        return star;
    }
}

测试类 

public class Demo361 {
    public static void main(String[] args) {
        //创建代理人
        Star proxy = ProxyUtil.createProxy(new BigStar("mona"));
        //使用代理人去调用方法
        System.out.println(proxy.sing("偶像宣言"));
        proxy.dance();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1294264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAP 后继物料简介

后继物料(Discontinued Part)是SAP系统提供的一项用于物料继承与物料永久性替换的功能。在企业的日常生产业务中,经常会出于技术原因或成本原因进行大批量的物料替换或物料升级。比如说,企业可以用一种可靠性更高的组件替换先前使用的组件,或者出于节省成本的目的,使用一…

Linux 多进程并发设计-进程对核的亲缘设置

1设计结构 2 设计优点 1 充分利用多核系统的并发处理能力2 负载均衡3 职责明确&#xff0c;管理进程仅负责管理&#xff0c;工作进程仅负责处理业务逻辑 3 演示代码: //main.cpp #define _GNU_SOURCE #include<sys/types.h> #include<sys/wait.h> #include <…

设计模式基础——概述(1/2)

目录 一、设计模式的定义 二、设计模式的三大类别 三、设计模式的原则 四、主要设计模式目录 4.1 创建型模式&#xff08;Creational Patterns&#xff09; 4.2 结构型模式&#xff08;Structural Patterns&#xff09; 4.3 行为型模式&#xff08;Behavioral Patterns&…

alma centos8 dvd 安装jumpserver堡垒机

安装脚本 # 更新系统yum update yum install -y wget curl tar gettext iptables# 安装jumpserver堡垒机curl -sSL https://resource.fit2cloud.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash安装过程 升级系统、安装需要的软件 安装jumpserve…

报错处理集

这个报错处理集的错误来源于编译arm平台的so文件产生的。但是后续可以补充成linux一个大的错误处理集。 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 第一次整理的时间是2023年12月8日10:05:59&#xff0c;以下错误来源于欧拉系统编译…

高端的露营装备网站搭建的作用是什么

近些年发展促进了露营热潮&#xff0c;周边游也多了起来&#xff0c;城市中高频工作带来的烦恼使得很多人想要放松&#xff0c;露营无疑是接触大自然很好的方式&#xff0c;而选择好的露营装备同样重要&#xff0c;还包括门店经营者&#xff0c;选择好的品牌合作也能带来很多生…

编程怎么学才能快速入门,分享一款中文编程工具快速学习编程思路,中文编程工具之分组框构件简介

一、前言&#xff1a; 零基础自学编程&#xff0c;中文编程工具下载&#xff0c;中文编程工具构件之扩展系统菜单构件教程 编程系统化教程链接 https://jywxz.blog.csdn.net/article/details/134073098?spm1001.2014.3001.5502 给大家分享一款中文编程工具&#xff0c;零基础…

VSCODE 运行C程序缓慢解决方法之一

最近更换了mingw的版本&#xff0c;安装路径与之前的mingw路径不大一样。结果发现代码运行的时候很慢&#xff0c;弹出窗口后&#xff0c;迟迟没有打印任何东西&#xff0c;就像卡死了一样。试过网上说的一堆方法&#xff0c;没有什么用。 我按照以下流程进行检查: 1.检查min…

苹果始终安全?未必!

传统印象中&#xff0c;苹果似乎始终以安全可靠著称。 但事实上&#xff0c;苹果公司并不乏安全事件。只是你可能从未意识到这些问题&#xff0c;甚至其中一些可能将你置于危险之中。那么&#xff0c;苹果经历过哪些黑客攻击、数据泄露和安全漏洞事件呢&#xff1f; 一、苹果的…

中断、异常和系统调用(2-1,2-2,2-3)

2-1 课堂练习2.1&#xff1a;外部中断 本实训分析 Linux 0.11 对外部中断的响应和处理过程。在每条指令执行的末尾&#xff0c;如果没有关中断&#xff0c;CPU 会检查是否收到了外部中断信号&#xff0c;如果有信号&#xff0c;则 CPU 就切换到核心态去执行对应的中断处理程序…

C语言第十六集(前)

1.关于那个整形存储入char的 是先取好补码,再截断 例: 2.%u是以十进制的形式打印无符号整数 3.注意(背):存储的char类型变量的补码为10000000的直接解析为-128 4.signed char 类型的变量取值范围是-128~127 5.unsigned char 类型的变量取值范围是0~255 6.有符号类型的变量…

编程创意汇聚地,打造个性作品集 | 开源日报 No.97

spring-projects/spring-boot Stars: 70.4k License: Apache-2.0 Spring Boot 是一个用于简化 Spring 应用程序开发的框架&#xff0c;它通过提供默认配置和约定大于配置的方式来减少开发者的工作量。Spring Boot 可以快速地创建独立的、生产级别的基于 Spring 框架的应用程序…

【论文合集】在非欧空间中的图嵌入方法(Graph Embedding in Non-Euclidean Space)

文章目录 1. Hyperbolic Models1.1 Hyperbolic Graph Attention Network1.2 Poincar Embeddings for Learning Hierarchical Representations.1.3 Learning Continuous Hierarchies in the Lorentz Model of Hyperbolic Geometry1.4 Hyperbolic Graph Convolutional Neural Net…

快速登录界面关于如何登录以及多账号列表解析以及config配置文件如何读取以及JsLogin模块与SdoLogin模块如何通信(4)

1、### Jslogin模块与前端以及JsLogin模块与Sdologin的交互 配置文件的读取: <CompanyIdForQq value"301"/> <CompanyIdForWx value"300"/><CompanyIdForWb value"302"/><qq value"https://graph.qq.com/oauth2.0/au…

使用Notepad++编辑器,安装AnalysePlugin搜索插件

概述 是一款非常有特色的编辑器&#xff0c;Notepad是开源软件&#xff0c;Notepad中文版可以免费使用。 操作步骤&#xff1a; 1、在工具栏 ->“插件”选项。 2、勾选AnalysePlugin选项&#xff0c;点击右上角“安装”即可。 3、 确认安装插件 4、下载插件 5、插件已安装…

【Linux】resolv.conf 文件

resolv.conf resolv.conf 文件 是 DNS 的 client 端使用的文件&#xff0c;用于设置 DNS 服务器的 ip 地址以及 DNS 域名&#xff0c;还可以配置域名搜索顺序等等。主要包含如下关键字&#xff1a;nameserver、domain、search、sortlist、options。设置的格式都是 关键字空格 …

Java期末复习题之抽象类、接口

点击返回标题->23年Java期末复习-CSDN博客 第1题. 首先设计一个学生抽象类Student&#xff0c;其数据成员有name(姓名)、age(年龄)和degree(学位)&#xff0c;以及一个抽象方法show()。然后由Student类派生出本科生类Undergraduate和研究生类Graduate&#xff0c;本科生类Un…

使用ES6 async awai t进行异步处理

我们往往在项目中会遇到这样的业务需求&#xff0c;就是首先先进行一个ajax请求&#xff0c;然后再进行下一个ajax请求&#xff0c;而下一个请求需要使用上一个请求得到的数据&#xff0c;请求少了还好说&#xff0c;如果多了&#xff0c;就要一层一层的嵌套&#xff0c;就好像…

AI自动生成代码工具

AI自动生成代码工具是一种利用人工智能技术来辅助或自动化软件开发过程中的编码任务的工具。这些工具使用机器学习和自然语言处理等技术&#xff0c;根据开发者的需求生成相应的源代码。以下是一些常见的AI自动生成代码工具&#xff0c;希望对大家有所帮助。北京木奇移动技术有…

小航助学2023年9月GESP_Scratch一级真题(含题库答题软件账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号 单选题3.00分 删除编辑附件图文 答案:C 第1题我们通常说的“内存”属于计算机部件中的( ) A、输出设备B、输入设备C、存储设备D、打印设备 答案解析&#xff1a; 单选题3…