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

目录

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

二.获取构造方法对象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();
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学习通【劳动通论】2023章节练习题

社会主义核心价值观24个字是&#xff1a;富强、民主、文明、和谐&#xff0c;自由、平等、公正、法治&#xff0c;爱国、敬业、诚信、友善。 1、“富强、民主、文明、和谐”&#xff0c;是我国社会主义现代化国家的建设目标&#xff0c;也是从价值目标层面对社会主义核心价值观…

超级实用的防止商品超卖的 7 种实现方式,非常好用!

高并发场景在现场的日常工作中很常见&#xff0c;特别是在互联网公司中&#xff0c;这篇文章就来通过秒杀商品来模拟高并发的场景。 本文环境&#xff1a; SpringBoot 2.5.7 MySQL 8.0 X MybatisPlus Swagger2.9.2 模拟工具&#xff1a; Jmeter 模拟场景&#xff1a; 减库…

2000字总结—Redis常见命令

与其明天开始&#xff0c;不如现在行动&#xff01; 文章目录 Redis常见命令通用命令String类型key的层级格式Hash类型List类型Set类型SortedSet类型 &#x1f48e;总结 Redis常见命令 通用命令 通过help[command]可以查看一个命令的具体用法 127.0.0.1:6379> help keysK…

鸿蒙应用开发ArkTS容器组件的使用

语雀知识库地址&#xff1a;语雀HarmonyOS知识库 飞书知识库地址&#xff1a;飞书HarmonyOS知识库 本文示例代码地址&#xff1a;Gitee 仓库地址 嗨&#xff0c;大家好&#xff0c;我是小白 上篇文章向大家介绍了 ArkTS 中我们经常使用到的几种基础组件&#xff0c;Text、Butt…

智能优化算法应用:基于教与学算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于教与学算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于教与学算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.教与学算法4.实验参数设定5.算法结果6.参考文…

【Python必做100题】之第三题(找出100以内的奇数并打印)

思路&#xff1a; 1、定义一个空列表来存储所有的奇数 2、判断是奇数就追加到列表的末尾 3、打印所有的奇数 代码如下&#xff1a; list [ ] #定义一个列表来存储所有的奇数 for i in range (1,100):if i % 2 ! 0: #判断是否为奇数list.append(i) #追加到列表的末尾 prin…

仿照MyBatis手写一个持久层框架学习

首先数据准备&#xff0c;创建MySQL数据库mybatis&#xff0c;创建表并插入数据。 DROP TABLE IF EXISTS user_t; CREATE TABLE user_t ( id INT PRIMARY KEY, username VARCHAR ( 128 ) ); INSERT INTO user_t VALUES(1,Tom); INSERT INTO user_t VALUES(2,Jerry);JDBC API允…

《信息技术时代》期刊杂志论文发表投稿

《信息技术时代》期刊收稿方向&#xff1a;通信工程、大数据、计算机、办公自动化、信息或计算机教育、电子技术、系统设计、移动信息、图情信息研究、人工智能、智能技术、信息技术与网络安全等。 刊名&#xff1a;信息技术时代 主管主办单位&#xff1a;深圳湾科技发展有限…

【sgAutocomplete】自定义组件:基于elementUI的el-autocomplete组件开发的自动补全下拉框组件(带输入建议的自动补全输入框)

特性&#xff1a; 1、支持本地保存选中过的记录 2、支持动态接口获取匹配下拉框内容 3、可以指定对应的显示label和字段组件key 4、自动生成速记符字段&#xff08;包含声母和全拼两种类型&#xff09;&#xff0c;增强搜索匹配效率 sgAutocomplete源码 <template><!…

API接口并发测试:如何测试API接口的最大并发能力?

本文将深入探讨API接口并发测试&#xff0c;介绍并比较不同的API并发测试工具&#xff0c;并分享如何有效测量和提高API接口在最大并发情况下的性能。了解如何应对高并发压力是保证系统稳定性和用户满意度的关键&#xff0c;让我们一起来探索这个重要的话题。 随着互联网的迅速…

selenium库的使用

来都来了给我点个赞收藏一下再走呗&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339; 目录 一、下载需要用到的python库selenium 二、selenium的基本使用 1.在python代码引入库 2.打开浏览器 3.元素定位 1&#xff09;通过id定位 2&#xff09;通过标…

计算机组成原理-指令寻址

指令寻址 指令 寻址下一条欲执行指令的地址&#xff08;始终由程序计数器PC给出) 顺序寻址 &#xff08;PC&#xff09;“1”-> PC 这里的1理解为1个指令字长&#xff0c;实际加的值会因指令长度、编址方式而不同 **跳跃寻址 **由转移指令指出 数据寻址 确定 本条指令 的…

AttributeError: module ‘lib‘ has no attribute ‘X509_V_FLAG_CB_ISSUER_CHECK‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

【Android12】Android Framework系列--AMS启动Activity分析

AMS启动Activity分析 通过ActivityManagerService(AMS)提供的方法&#xff0c;可以启动指定的Activity。比如Launcher中点击应用图标后&#xff0c;调用AMS的startActivity函数启动应用。 AMS提供的服务通过IActivityManager.aidl文件定义。 // frameworks/base/core/java/an…

智能优化算法应用:基于郊狼算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于郊狼算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于郊狼算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.郊狼算法4.实验参数设定5.算法结果6.参考文献7.MA…

关于IDEA中maven的作用以及如何配置MAVEN

关于IDEA中maven的作用以及如何配置MAVEN 1、Maven是什么2、Idea中对于Maven的配置3、下载依赖时&#xff0c;Idea下方的显示3.1、Maven中央仓库的下载显示界面3.2、阿里云仓库的下载显示界面 4、Maven在Idea中的使用4.1、clean4.2、validate4.3、compile4.4、test&#xff08;…

pyqt5使用Designer实现按钮上传图片

pyqt5使用Designer实现按钮上传图片 1、ui界面 2、ui转py代码 其中uploadimg.py代码如下&#xff1a; # -*- coding: utf-8 -*-# Form implementation generated from reading ui file uploadimg.ui # # Created by: PyQt5 UI code generator 5.15.4 # # WARNING: Any manua…

git 使用记录

远程仓库为空初始化 初始化本地仓库 git init 在本地仓库书写代码&#xff08;这里可以编辑一个文本文件做测试&#xff0c;如hello.txt&#xff09; 5&#xff09;执行&#xff1a;git add 要让git管理的文件&#xff08;git add hello.txt&#xff09;>执行完此操作将我…

有趣的数学 用示例来阐述什么是初值问题一

一、初值问题简述 在多变量微积分中&#xff0c;初值问题是一个常微分方程以及一个初始条件&#xff0c;该初始条件指定域中给定点处未知函数的值。在物理学或其他科学中对系统进行建模通常相当于解决初始值问题。 通常给定的微分方程有无数个解&#xff0c;因此我们很自然地会…

Linux 基础IO

文章目录 前言基础IO定义系统IO接口文件描述符重定向原理缓冲区刷新 前言 要知道每个函数/接口的全部参数和返回值建议去官网或者直接在Linux的man手册中查&#xff0c;这不是复制粘贴函数用法的文章。 C语言文件读写介绍链接 基础IO定义 IO是Input/Output的缩写&#xff0c…