反射复习(java)

文章目录

  • 反射机制的作用
  • 反射机制的原理
    • 加载机制详细解释
  • 获取 Class 对象
  • 反射获取构造方法:获取 Class 对象里面 Constructor 对象
  • 反射获取成员变量:获取Class 对象里面的 Field 对象
  • 反射获取成员方法:获取 Class 对象里的 Method 对象
  • 其他常用 API

前言

反射非常重要,一定要掌握,我个人觉得不是很难,就是要注意各种方法里的参数是什么,然后还是那句话:最快的入门方式是看视频,建议先看完视频,再来看博客,这里我推荐 b 站韩顺平老师的视频

反射机制的作用

作用看不懂的话可以最后看

反射可以在不修改源码的情况下来控制程序符合 ocp 原则 :不修改源码,扩容功能


举个例子

现在有一个 main 类 和 Person 类,还有一个配置文件my.Properties,可以利用反射通过中间的 my.Properties 访问类中的东西

my.Properties

Classfullpath = com.mangfu.Person
field = name

Person

public class Person {
    public String name = "jack";
    public int age = 13;

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

}

Main

public class Main {
    public static void main(String[] args) throws Exception{

        //导入配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src/com/mangfu/my.Properties"));

        //通过配置文件获取 类的完整路径, 和类的属性名
        String classfullpath = properties.getProperty("Classfullpath");
        String field = properties.getProperty("field");

        //通过反射获取到 Person类的字节码对象,我们可以操作里面所有的东西
        Person person = new Person();
        Class clazz = Class.forName(classfullpath);

        //这里直接操作类里面的属性
        //本来是要 person.name 改成 person.age
        //现在直接在配置文件中的 name 改成 age就行了
        Field field1 = clazz.getField(field);
        System.out.println(field1.get(person));

    }
}

可以看见我们可以通过中间的 配置文件 无需修改源码,就能操作类中的信息




反射机制的原理

在这里插入图片描述

编译的时候会产生字节码文件,然后通过类加载器,进入加载阶段,会在堆区创建一个 Class 类的对象,当然这个Class对象里面的成员变量,构造器,构造方法等东西都是对象,然后 到 new Cat(),在 堆区创建 Cat 对象,该对象知道他属于哪个 Class 对象,我们可以通过反射得到这个 Class 对象,然后操作类中的所有东西

注意一个类只有一个 Class 对象



加载机制详细解释

类加载过程图
在这里插入图片描述


Loading(加载)

JVM 将 字节码文件 从 不同 的 数据源,转化为 二进制字节流,加载到内存中,生成一个代表该类的 Class 对象,也就是这个类的对象


verification(验证)

为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,,不会危害虚拟机自身的安全,这个阶段会 进行文件格式验证 **(是否以魔数 oxcafebabe开头),元数据验证,字节码验证,和符号引用验证

如果想要关闭大部分类验证措施,加快加载速度可以这样做

javac -Xverify:none HelloWorld.java

helloworld 是类名


Preparation(准备)

JVM 会在该阶段 对 静态变量!!!,分配内存并初始化(对应数据类型的默认初始值)。这些变量的 内存分配在方法区

注意这里是静态变量,不是静态的,加载阶段不会分配内存


Resolution (解析)

JVM 将常量池的 == 符号引用== 替换为 直接引用的过程

符号引用

将 Java 类文件中,以一组符号来描述类名,方法名等东西,这些符号与实际的内存地址没有关系

直接引用

将符号引用,直接替换为直接指向这些数据的指针或地址

还没分配内存的时候用符号引用类似于打个标记,这个时候分配内存在变成直接引用


initialization(初始化)

这个阶段才真正执行类中定义的 Java 程序代码,这个阶段也是执行 clinit() 方法的过程,这个方法会根据顺序,把静态变量的赋值动作,和静态代码块中的语句合并

clinit 方法在多线程的环境中会正确加锁,也就是线程是阻塞的,等一个线程 clinit 方法执行完,才放锁,让下一个线程用




获取 Class 对象

  • Class.forName(“全类名”):编译阶段创建
    全类名:包名 + 类名

多用于配置文件,最常用

//com.mangfu.test 包下的 Student 类
Class test = Class.forName("com.mangfu.test.Student" );

  • 类名.class:加载阶段创建,类加载器得到 Class 对象

多用于参数传递,比如通过反射得到对应构造器对象,这种方式 最安全,性能最高

Class clazz = Student.class

  • 对象.getClass():运行阶段创建

通过创建好的对象,获取 Class 对象

Student s = new Student();
Class clazz = s.getClass();

  • 基本数据类型.class

基本数据类型,创建 Class 对象的方法

Class clazz = int.class

  • 包装类.TYPE

基本数据类型对应的包装类,创建 Class 对象的放啊

Class clazz = Integer.class



反射获取构造方法:获取 Class 对象里面 Constructor 对象

Class类 中用于获取构造方法的方法

  • Constructor<?>[] getConstructors(): 返回所有公有构造方法对象的数组

  • Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组

  • Constructor getConstructor(Class<?>… parameteTypes):返回单个公有构造方法对象
    参数为 基本数据结构或者包装类的字节码,对象.class,这样可以获取有参构造

  • Constructor getDeclaredConstructor(Class<?>…parmeterTypes):返回单个构造方法对象
    参数为 基本数据结构或者包装类的字节码,对象.class,这样可以获取有参构造

Constructor:用构造方法对象创建对象的方法
Student类

  • T newinstance(Object…initargs):根据指定的构造方法创建对象
    参数(可变):是构造函数里面需要的参数

  • setAccessible(boolean flag):设置为 true, 表示取消访问检查

setAccessible:**使用反射可以访问 private 构造器 [称为爆破]


举个例子
主要看Main类

Student类

public class Student {
    private int age = 18;
    public String name = "张三";

    private Student() {}

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

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

Main 类

public class Main {
    public static void main(String[] args)throws Exception {
        Class clazz = Class.forName("com.mangfu.test.Student");

        //因为 构造方法是私有的 所以我们要用 getDeclaredConstructor
        //里面的参数是 形参的字节码
        Constructor cs = clazz.getDeclaredConstructor(int.class, String.class);

        //因为这个是私有对象,我们要通过爆破创建才能构造一个对象
        cs.setAccessible(true);

        //通过 newInstance 构造一个对象
        Student s = (Student) cs.newInstance(18, "张三");
        System.out.println(s);

    }
}


反射获取成员变量:获取Class 对象里面的 Field 对象

Class 类中用于获取成员变量的方法

  • Field[] getFields():返回所有公共成员变量对象的数组

  • Field[] getDeclaredFields():返回所有成员变量对象的数组

  • Field[] getField(String name):返回单个公有成员变量对象
    参数是 对象(不是Class对象,下面是Student 对象) 的属性名

  • Field getDeclaredField(String name):返回单个成员变量对象
    参数是 对象(不是Class对象,下面是Student 对象) 的属性名

Field 类中用于创建对象的方法

  • void set(Object obj, Object value):赋值
    参数1:field 对象,参数2:需要赋的值

  • Object get(Object obj):获取值
    参数:对象(不是Class 对象,下面是 Student 对象)的名字

  • setAccessible(boolean flag):设置为 true, 表示取消访问检查

举例
Student 类

public class Student {
    private int age = 18;
    private String name = "张三";

    private Student() {}

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

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

Main类

public class Main {
    public static void main(String[] args)throws Exception {

        //得到 Student 类的 Class 对象
        Class clazz = Class.forName("com.mangfu.test.Student");

        //获取 Class 对象里面的 Field 对象----属性 name
        Field field = clazz.getDeclaredField("name");

        //通过 反射利用构造函数构造对象
        Constructor cs = clazz.getDeclaredConstructor(int.class, String.class);
        cs.setAccessible(true);
        Student s = (Student) cs.newInstance(18, "张三");

        //因为这个属性是私有的 所以要用 setAccessible 爆破一下,才能修改
        field.setAccessible(true);

        //修改 属性 name 的 值,因为上面我们获取的 是属性 name 对象
        field.set(s, "李四");
        System.out.println(field.get(s));//输出李四

    }
}


反射获取成员方法:获取 Class 对象里的 Method 对象

Class类中用于获取成员方法的方法

  • Method[] getMethods():返回公有成员方法对象的数组,包括继承的

  • Method[] getDeclaredMethods:返回所有成员方法对象的数组,不包括继承的

  • Method getMethod(String name, Class<?>…parameterTypes):返回单个公有成员方法对象
    参数1:方法的名字,参数2:方法的形参(可变)

  • Method getDeclaredMethod(String name, Class<?>…parameterTypes):返回单个成员方法对象
    参数1:方法的名字,参数2:方法的形参(可变)

Method类中用于创建对象的方法

  • Object invoke(Object obj, Object…args):允许方法
    参数1: 对象(不是Class对象,下面是Student 对象),参数2:调用方法要传递的参数(没有就不写)。返回值:调用的方法的返回值的对象

  • setAccessible(boolean flag):设置为 true, 表示取消访问检查

举例
Student 类

public class Student {
    private int age = 18;
    private String name = "张三";

    public Student() {};

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

    private int hi() {
        System.out.println("调用hi函数");
        return 1;
    }

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

Main 方法

public class Main {
    public static void main(String[] args)throws Exception {

        //得到 Student 类的 Class 对象
        Class clazz = Class.forName("com.mangfu.test.Student");

        //得到 Student 中的 hi 方法的对象
        Method method = clazz.getDeclaredMethod("hi");

        //这里 通过反射 构造 Student 类对象
        Constructor constructor = clazz.getConstructor();
        Student s = (Student) constructor.newInstance();

        //通过反射调用 Student 类中的 hi 方法,因为我们上面的得到的 Method 对象是 hi 方法
        //而且这个方法是私有的所以要爆破一手
        method.setAccessible(true);
        method.invoke(s);

    }
}



其他常用 API

Class
在这里插入图片描述


Constructor

Parmeter[] getrParmameters():获取构造方法的形参

int getmodifiers():获取成员变量的数据类型


Field

int getmodifiers():获取成员变量的数据类型
Class<?> getType:获取成员变量的数据类型
String getName:获取成员变量的名字


Method

int getmodifiers():获取成员变量的数据类型
Class[] getExceptionTypes:获取方法抛出的异常
String getName:获取成员变量的名字
Class[] getParameter():获取方法的形参,以 Class[] 形式返回
Class getReturnType:以Class 形式获取返回类型


getmodifiers() 方法返回值

默认修饰符号:0,public:1,private:2,protected:3,static:8,final:16




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

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

相关文章

C#聊天室客户端完整③

窗体 进入聊天室界面(panel里面,label,textbox,button): 聊天界面(flowLayoutPanel(聊天面板))&#xff1a; 文档大纲(panel设置顶层(登录界面),聊天界面在底层) 步骤&#xff1a;设置进入聊天室→输入聊天→右边自己发送的消息→左边别人发的消息 MyClient.cs(进入聊天室类) …

轮式机器人Swiss-Mile城市机动性大提升:强化学习引领未来城市物流

喜好儿小斥候消息&#xff0c;苏黎世联邦理工学院的研究团队成功开发了一款革命性的机器人控制系统&#xff0c;该系统采用强化学习技术&#xff0c;使轮式四足机器人在城市环境中的机动性和速度得到了显著提升。 喜好儿网 这款专为轮腿四足动物设计的控制系统&#xff0c;能…

crmeb Pro版/多店版商城付费会员、会员卡功能说明

一、功能介绍 用户开通付费会员后&#xff0c;可获得多项商城优惠&#xff0c;商家可通过此功能锁定重要客户&#xff0c;培养客户消费习惯等 二、操作流程 用户 &#xff1e; 会员管理 &#xff1e; 付费会员 三、功能说明 1. 会员类型 付费卡类型&#xff1a;月卡、季卡…

【电机控制】FOC算法验证步骤——PWM、ADC

【电机控制】FOC算法验证步骤 文章目录 前言一、PWM——不接电机1、PWMA-H-50%2、PWMB-H-25%3、PWMC-H-0%4、PWMA-L-50%5、PWMB-L-75%6、PWMC-L-100% 二、ADC——不接电机1.电流零点稳定性、ADC读取的OFFSET2.电流钳准备3.运放电路分析1.电路OFFSET2.AOP3.采样电路的采样值范围…

RNN-循环神经网络

1.前者的输出作为后者的输入&#xff08;循环&#xff09;&#xff0c;有先后关系的信息&#xff0c;前影响后&#xff0c;时间序列。处理数字信息。 2.独热编码 ont-hot Encoding&#xff1a;处理的文字数据地位相同&#xff0c;相当于用二进制数01给数据编码&#xff0c;会增…

学习笔记——网络管理与运维——SNMP(SNMP原理)

四、SNMP原理 SNMP的工作原理基于客户端-服务器模型。其中&#xff0c;网络管理系统是客户端&#xff0c;而网络设备是服务器。客户端向服务器发送请求消息(即"Get"或"Set"命令)来获取或修改服务器的信息。服务器收到请求消息后&#xff0c;会返回相应的响…

使用volta管理前端开发环境

背景&#xff1a;公司有新老不同的产品&#xff0c;使用的node版本不一样&#xff0c;每次都要手动切换node版本&#xff0c;对应的项目才能运行。这样很麻烦&#xff0c;有没有好的解决方法&#xff0c;就找到了volta。 1.为什么是volta&#xff1f; 管网介绍&#xff1a;使用…

中文翻译藏语的软件都有哪些?分享3款实用的!

在数字化时代&#xff0c;语言不再是沟通的障碍。随着科技的飞速发展&#xff0c;中文翻译藏语的软件层出不穷&#xff0c;为那些对藏族文化感兴趣或需要在藏区工作、旅行的人们提供了极大的便利。本文将为您盘点几款热门的中文翻译藏语软件&#xff0c;助您轻松跨越语言鸿沟。…

AMEYA360代理:纳芯微NSOPA240x系列破解旋转变压器之“难”

随着市场对高精度、高性能电机控制技术的不断追求&#xff0c;旋转变压器作为其核心部件之一&#xff0c;其精确测量角度位置和转速的能力显得尤为重要。 然而&#xff0c;旋转变压器驱动电路的特殊要求一直是行业发展的技术瓶颈。为解决这一挑战&#xff0c;纳芯微近日发布了全…

抖音a_bogus,mstoken全参数爬虫逆向补环境2024-06-15最新版

抖音a_bogus,mstoken全参数爬虫逆向补环境2024-06-15最新版 接口及参数 打开网页版抖音&#xff0c;右键视频进入详情页。F12打开控制台筛选detail&#xff0c;然后刷新网页&#xff0c;找到请求。可以发现我们本次的参数目标a_bogus。a_bogus有时长度为168有时为172&#xf…

Node.js安装扫盲

一、Node.js安装 在官网下载node.js安装包 双击打开node-v20.14.0-x64.ms文件&#xff0c;点击运行 进入安装Node.js的对话框&#xff0c;点击Next继续 勾选复选框后点击Next继续 默认安装路径 默认配置 这里不需要勾选&#xff0c;直接点击Next 点击Install 二、Node.js验…

PyQt5和Eric7的安装使用 —— Python篇

需要安装Python的朋友请看另一篇文章&#xff1a; windows系统安装Python -----并安装使用Pycharm编辑器 一、安装PyQt5&#xff1a; 1、方法一&#xff1a;使用pip命令在线安装。 输入以下命令可以直接安装&#xff1a; pip install PyQt5 由于安装默认使用国外的镜像&a…

【免费Web系列】大家好 ,今天是Web课程的第二二天点赞收藏关注,持续更新作品 !

这是Web第一天的课程大家可以传送过去学习 http://t.csdnimg.cn/K547r 员工管理 1. 修改员工 对于修改功能&#xff0c;分为两步实现&#xff1a; 点击 “编辑” 根据ID查询员工的信息&#xff0c;回显展示。 点击 “保存” 按钮&#xff0c;修改员工的信息 。 1.1 回显…

行业透视 | ERP系统成熟度评判:五个关键能力解析-亿发

在现代企业管理中&#xff0c;ERP系统&#xff08;企业资源计划系统&#xff09;已成为不可或缺的工具。然而&#xff0c;什么样的ERP系统才算是成熟的&#xff1f;以下几个关键能力&#xff0c;是一个成熟的ERP系统所必备的&#xff0c;缺一不可。 数据一体化&#xff0c;远离…

RT-Thread简介及启动流程分析

阅读引言&#xff1a; 最近在学习RT-Thread的内部机制&#xff0c;觉得这个启动流程和一些底层原理还是挺重要的&#xff0c; 所以写下此文。 目录 1&#xff0c; RT-Thread简介 2&#xff0c;RT-Thread任务的几种状态 3&#xff0c; 学习资源推荐 4&#xff0c; 启动流程分…

[element-ui]el-select多选选择器选中其中一个选项,不可删除

背景&#xff1a; 产品真的很多奇奇怪怪的需求&#xff0c;一边吐槽一边实现。 前提&#xff1a;选择器作为表格的筛选项&#xff0c;提供三个选项值。 要求&#xff1a;默认选中其中一个值&#xff0c;这个值不可删除。 如图&#xff1a; 小声吐槽&#xff1a;搞这些有什么…

Mobaxterm 配置 ssh 隧道

背景介绍&#xff1a; 在使用 ssh远程 连接服务器时&#xff0c;由于许多服务器并没有公网ip&#xff0c;或者不能从内部直接访问&#xff0c;经常使用 跳板机端口转发 的形式访问服务器。 但是在实际使用中&#xff0c;我们经常会有些网络和数据交换操作&#xff0c;需要用到…

【刷题】LeetCode刷题汇总

目录 一、刷题题号1&#xff1a;两数之和 二、解法总结1. 嵌套循环2. 双指针 一、刷题 记录LeetCode力扣刷题 题号1&#xff1a;两数之和 双循环&#xff08;暴力解法&#xff09;&#xff1a; class Solution {public int[] twoSum(int[] nums, int target) {int[] listne…

仪表运放输入端抗RFI滤波器设计注意事项

1 概述 有个潜在问题却往往被忽视&#xff0c;即仪表放大器中存在的射频整流问题。当存在强射频干扰时&#xff0c;集成电路的内部结点可能对干扰进行整流&#xff0c;然后以直流输出失调误差表现出来&#xff1b; 2 共模和差模输入滤波器 该滤波器针对CM(R1-C1和R2-C2)&#…

快去复习吧+++常用算法及参考算法 递推法++穷举法++排序(冒泡、选择)++查找(顺序、折半)++字符串处理++方程求根++无穷级数求和

接上&#xff1a;常用算法及参考算法 &#xff08;1&#xff09;累加 &#xff08;2&#xff09;累乘 &#xff08;3&#xff09;素数 &#xff08;4&#xff09;最大公约数 &#xff08;5&#xff09;最值问题 &#xff08;6&#xff09;迭代法 常用算法及参考算法 7. 递推法…