Java反射专题

news2024/11/24 17:48:09

目录

一.反射机制

1.Java Reflection

2.反射相关的主要类

3.反射的优缺点

4.反射调用优化—关闭访问检查

二.Class类

1.基本介绍

2.常用方法

3.获取Class对象的方式

4.那些类型有Class对象

三.类加载

1.介绍

2.类加载时机

3.类加载各阶段

四.获取类结构的信息

1. java.lang.Class类

2. java.lang.reflect.Field类

五.反射暴破

1.介绍

2.反射暴破构造器

3.反射暴破操作属性

4.反射暴破操作方法


一.反射机制

1.Java Reflection

反射机制允许程序在执行期借助于ReflectionAPI获取任何类的内部信息(比如成员变量,构造器,成员方法等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。

加载完类后,在堆中就产生了一个Class类型的对象,这个对象包含了类的完整结构信息。通过这个对象得到类的结构。

下面是反射的原理图:

后面的内容也会用到这个图。

2.反射相关的主要类

说明

java.lang.Class代表一个类,Class对象表示某个类加载后在堆中的对象
java.lang.reflect.Method代表类的方法,Method对象表示某一个类的方法
java.lang.reflect.Field代表类的成员变量,Field对象表示某个类的成员变量
java.lang.reflect.Constructor代表类的构造方法,Constructor对象表示构造器

3.反射的优缺点

优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。

缺点:使用反射基本是解释执行,对执行速度有影响。

4.反射调用优化—关闭访问检查

Method、Field和Constructor对象都有setAccessible()方法。setAccessible()的作用是启动和禁用访问安全检查的开关。参数为true表示反射的对象在使用是取消访问检查,提高反射的效率。参数为false则表示反射的对象执行访问检查。

二.Class类

1.基本介绍

Class也是类,也继承于Object类。Class类不是new出来的,而是系统创建的。对于某一个类的Class对象,在内存中只有一份,因此类只加载一次。每个类的实例都会记得自己是由哪个Class实例所完成。通过Class对象可以完整地得到一个类的完整结构。类的字节码二进制数据,是放在方法区的。

2.常用方法

方法说明
forName(String name)返回指定类名 name 的 Class 对象
newInstance()调用缺省构造函数,返回给Class对象的一个实例
getName()返回此Class对象所表示的实体名称
getSuperClass()返回当前Class对象的父类的Class对象
getInterfaces()获取当前Class对象的接口
getClassLoader()返回该类的类加载器
getSuperclass()返回表示此Class所表示的实体的超类的Class
getConstructors()返回一个包含某些Constructor对象的数组
getDeclaredFields()返回Field对象的一个数组
getMethod(String name,Class ...paramType)返回一个Method对象,此对象的形参类型为paramType

应用示例:

String classAllPath="newBag.Cat";
//1.获取Cat类 对应的Class对象
Class<?> cls = Class.forName(classAllPath);
//2.输出cls
System.out.println(cls);    //显示cls对象,是哪个类的Class对象
System.out.println(cls.getClass());     //输出cls运行类型
//3.得到包名
System.out.println(cls.getPackage().getName());
//4.得到全类名
System.out.println(cls.getName());
//5.通过cls创建对象实例
Cat cat=(Cat) cls.newInstance();
System.out.println(cat);
//6.通过反射获取属性brand
Field name = cls.getField("name");
System.out.println(name.get(cat));
//7.通过反射给属性赋值 name
name.set(cat,"大橘");
System.out.println(name.get(cat));
//8.得到所有的属性(字段)
Field[] fields = cls.getFields();
for(Field f:fields){
    System.out.println(f.getName());
}

3.获取Class对象的方式

1)已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法 forName() 获取。应用场景:多用于配置文件,读取类全路径,加载类。

补充:全类名(Fully Qualified Class Name)是一个类的完整名称,它包含了类所在的包名以及类名本身。全类名的目的是在整个Java程序或Java环境中唯一地标识一个类。

String classAllPath="newBag.Cat";
Class cls=Class.forName(classAllPath);

2)若已知具体的类,通过类的class获取,该方法最为安全可靠,程序性能最好。应用场景:多用于参数传递,比如通过反射得到对应构造器对象。

Class cls=类名.class;
Class cls= Cat.class;

3)已知某个类的实例,调用该实例的getClass()方法获取。应用场景:通过创建好的对象,获得Class对象。

Cat cat = new Cat();
Class cls = cat.getClass();

4)通过类加载器获取。

ClassLoader cl=对象.getClass().getClassLoader();
Class clazz=cl.loadClass("类的全类名");

String classAllPath="newBag.Cat";
Cat cat = new Cat();
ClassLoader classLoader = cat.getClass().getClassLoader();
Class cls = classLoader.loadClass(classAllPath);

5)基本数据(int等)使用 Class cls=基本数据类型.class;

Class cls=基本数据类型.class;
Class<Integer> integerClass = int.class;

基本数据类型对应的包装类,使用 Class cls=包装类.TYPE;

Class cls=包装类.TYPE;
Class<Integer> type = Integer.TYPE;

4.那些类型有Class对象

1)外部类,成员内部类,静态内部类,局部内部类,匿名内部类;2)interface:接口;3)数组;4)enum:枚举;5)annotation:注解;6)基本数据类型;7)void。

三.类加载

1.介绍

反射机制是Java实现动态语言的关键,也就是通过反射实现类动态加载。

加载有两种类型:

静态加载:编译时加载相关的类,如果没有则报错,依赖性太强。

例子:

public static void main(String[] args){
    Scanner scan=new Scanner(System.in);
    String str=scan.nextLine();
    switch (str){
        case "1":
            Dog dog=new Dog();
            break;
        case "2":
            System.out.println("输入了2");
            break;
    }
}

我们并没有写Dog类,搜易编译器会报错,告诉我们没有Dog类。这就是静态加载,即在编译时就加载了,没有写直接告诉我们错了。

动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在也不会报错,降低了依赖性。

例子:

public static void main(String[] args) throws ClassNotFoundException {
    Scanner scan=new Scanner(System.in);
    String str=scan.nextLine();
    switch (str){
        case "1":
            System.out.println("输入了1");
            break;
        case "2":
            Class cat = Class.forName("Cat");
            break;
    }
}

我们没有写Cat类,但是编译器不会报错。接着我们运行代码,只要我们不选2,就不会报错。只有选了2,才会出现错误。这就是动态加载,不用就没事。

2.类加载时机

1)当创建对象时(new)进行静态加载;

2)当子类被加载时,父类也加载(静态加载);

3)调用类中的静态成员时进行静态加载;

4)通过反射加载类是动态加载。

3.类加载各阶段

3.1 加载

JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、jar包等)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象

3.2 验证

目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机本身的安全。包含:文件格式验证(是否以oxcafebabe开头)、元数据验证、字节码验证和符合引用验证

3.3 准备

JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0、0L、null、false等)。这些变量所使用的内存都将在方法区中进行分配

//n1是实例属性,不是静态变量,在准备阶段不会分配内存
public int n1=10;
//n2是静态变量,分配内存;n2默认初始化为0,而不是10
public static int n2=10;

3.4 解析

虚拟机将常量池内的符号引用替换为直接引用的过程

3.5 初始化

到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行<clinit>()方法的过程。

什么是<clinit>()方法呢?

<clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。

四.获取类结构的信息

1. java.lang.Class类

方法说明
getName()获取全类名
getSimpleName()获取简单类名
getFields获取所有public修饰的属性,包含本类以及父类的
getDeclaredFields获取本类中的所有属性
getMethods获取所有public修饰的方法,包含本类以及父类的
getDeclaredMethods获取本类中所有方法
getConstructors获取所有public修饰的构造器,包含本类,没有父类
getDeclaredConstructors获取本类中所有构造器
getPackage以Package形式返回 包信息
getSuperClass以Class形式返回父类信息
getInterfaces以Class[]形式返回接口信息
getAnnotations以Annotation[]形式返回注解信息

2. java.lang.reflect.Field类

方法说明
getModifiers以int形式返回修饰符 ,返回0是默认修饰符,1是public,2是private,4是protected,8是static,16是final
getType以Class形式返回类型
getName返回属性名

五.反射暴破

1.介绍

首先我要知道这个反射暴破是干什么的?

暴破即暴力破解,我们可以通过暴破操作一些私有属性(private)的构造器、属性和方法。

2.反射暴破构造器

Class类相关方法:

newInstance:调用类中的无参构造器,获取对应类的对象

getConstructor(Class...):根据参数列表,获取对应的构造器对象

getDecalaredConstructor(Class...):根据参数列表,获取对应构造器对象

Constructor类相关方法:

setAccessible:暴破

newInstance(Object...):调用构造器

//例子
Class<?> cls = Class.forName("User");

Constructor<?> constructor = cls.getDeclaredConstructor(String.class, int.class);

constructor.setAccessible(true);

Object o = constructor.newInstance("Tom", 13);

System.out.println(o);

3.反射暴破操作属性

暴破:setAccessible(true)。

访问:set(o,值)和get(o)。

如果属性是静态的,set和get中的参数o可以写成null。

Class<?> cls = Class.forName("Person");

Object o = cls.getConstructor(String.class, int.class).newInstance("Tom", 0);

Field age = cls.getDeclaredField("age");

age.setAccessible(true);

age.set(o,14);

System.out.println(o);

4.反射暴破操作方法

暴破:setAccessi(true);

访问:invoke(o,参数列表);如果是静态方法,这里的o可以换从null

Class<?> student = Class.forName("Student");

Method getIm = student.getDeclaredMethod("getIm", int.class, String.class);

getIm.setAccessible(true);

getIm.invoke(null,13,"Tom");

//下面是getIm方法
private static void getIm(int age,String s){
    System.out.println(age+" "+s);
}

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

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

相关文章

25.第二阶段x86游戏实战2-背包属性补充

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

机器学习项目——运用机器学习洞察青年消费趋势

1. 项目背景 在21世纪的第三个十年&#xff0c;全球经济和技术的飞速发展正深刻影响着各个领域&#xff0c;尤其是青年消费市场。随着数字化进程的加速&#xff0c;尤其是移动互联网的广泛普及&#xff0c;青年的消费行为和生活方式发生了前所未有的转变。 然而&#xff0c;面对…

开源版GPT-4o来了!互腾讯引领风潮,开源VITA多模态大模型,开启自然人机交互新纪元[文末领福利]

目录 总览 VITA 模型的详细介绍 2.1 LLM 指令微调 2.2 多模态对齐 2.2.1 视觉模态 2.3 音频模态 多模态指令微调 3.1 训练数据 3.1.1 训练过程 模型部署&#xff1a;双工策略 4.1 非唤醒交互 4.2 音频中断交互 评估 5.1 语言表现 5.2 音频表现 5.3 多模态表现 …

离散微分几何中的网格(Meshes)

https://zhuanlan.zhihu.com/p/893338073 一、引言 ![](https://img-blog.csdnimg.cn/img_convert/c5e06e652822e0003cf6be91d26436b7.png) 在离散微分几何的广袤领域中&#xff0c;网格&#xff08;Meshes&#xff09;作为一个核心概念&#xff0c;犹如一座桥梁&#xff0c;…

小灰:从0到年入100万+,从程序员到自由职业者他经历了什么?

这是开发者说的第20期&#xff0c;这次给大家带来的畅销书《漫画算法》作者、自媒体创作者程序员小灰。 小灰做自媒体的时间已经有8年了&#xff0c;目前在全网有60w粉丝&#xff0c;同时《漫画算法》系列和《漫画ChatGPT》的书籍&#xff0c;在全网卖了12万册&#xff0c;靠写…

rocky9 samba共享

1. 安装samba服务&#xff0c;设置开机自启。 2. 创建四个用户user1&#xff0c;user2&#xff0c;sale1&#xff0c;manager&#xff0c;user1&#xff0c;user2属于finance组&#xff0c;sale1属于sales组&#xff0c;manager属于manager组。 3. 建立共享目录/opt/finance_…

模版进阶 非类型模版参数

一.模板参数分类类型形参与非类型形参。 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将该参数当成常量来使用。 #i…

打印1000年到2000年之间的闰年

我们要打印1000年到2000年之间的闰年&#xff0c;首先我们先输出1000年到2000年之间的所有的年份&#xff0c;同时我们将闰年的判断方法输入到其中 闰年需要满足下列两个条件的其中之一&#xff1a; 1.能被4整除但不能被100整除 2.能被400整除 打印1000年到2000年之间的闰年…

PCL 贪婪三角投影三角化

目录 一、概述二、代码三、结果 一、概述 PCL中贪婪三角投影三角化的简单使用案例 二、代码 greedy_projection.cpp #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include <pcl/search/kdtree.h> // for KdTree #include <pcl/features/…

【软件系统架构设计师-案例-1】架构风格

1. 请用200字以内说明系统可靠性的定义及包含的4个子特性&#xff0c;并简要指出提高系统可靠性一般采用哪些技术&#xff1f; &#xff08;1&#xff09;可靠性定义&#xff1a;系统在规定的时间或环境条件下&#xff0c;完成规定功能的能力&#xff0c;就是系统无故障运行的…

【AD速成】半小时入门AltiumDesigner(速通基础)

一.创建工程 1.工程 文件->新的->项目 PCB选择<Default>Project Name填入自己的工程名称Folder选择工程保存的路径 创建后如图&#xff1a; 这里的.prjPcb的文件即为AD的工程文件。 如果没有Project栏可以在视图->面板->Projects中勾选Projects CtrlS保存工…

Java学习-JVM调优

目录 1. JDK工具包 1.1 jps 1.2 jstat 1.3 jinfo 1.4 jmap 1.5 jhat 1.6 jstack 1.7 VisualVM 2. 第三方工具 2.1 GCEasy 2.2 MAT 2.3 Arthas 3. JVM参数 3.1 标准参数 3.2 非标准参数 3.3 不稳定参数 4. 调优 4.1 什么时候调优 4.2 调优调什么 4.3 调优原…

LINUX 系统管理操作

基础编辑 Tab 单击一次补全 双击列举候选 CTRL U 删除光标前 K 删除光标后 L 清屏&#xff08;只剩新命令行&#xff09; C 取消当前操作 反斜杠“\” 在需要转行的时候输入反斜杠 “\”回车 在>后继续输入 帮助命令 help 命令 大部分内建命令 格式&#xff1a;h…

直播预告 | 药品安全与合规保障难?智能温度监测助您领先制药工业4.0!

您是否在为温度敏感药品的运输和存储合规而苦恼&#xff1f; 是否担心冷链物流中的温度监控漏洞导致药品质量下降&#xff1f; 制药环境中的温湿度监控是否让您无从下手&#xff1f; 这些问题不仅影响药品的安全性&#xff0c;也直接影响企业的合规性和市场竞争力。如何确保环…

Android 保存图片到相册却不在“照片”中显示,只在相簿中显示

背景 需要从网络上下载图片到本地&#xff0c; 并显示在相册中 问题 将图片保存到内存中&#xff0c; 通过媒体API插入到媒体库后&#xff0c;图片只在“相簿”中的“所有项目”中显示&#xff0c;第一个页面的“照片”却不显示 解决办法 图片被保存到 Pictures/AppName 目录…

Linux系统通过编辑crontab来设置定时任务---定时关机

在Linux系统中&#xff0c;crontab 是用来设置周期性被执行的指令的守护进程。通过编辑 crontab&#xff0c;您可以安排定时任务&#xff0c;比如定时关机、定时备份文件、定时运行脚本等。以下是如何编辑 crontab 来设置定时任务的步骤&#xff1a; 打开终端&#xff1a;您可以…

基于springboot+vue的在线宠物用品交易网站

一、系统架构 前端&#xff1a;vue | element-ui | html 后端&#xff1a;springboot | mybatis-plus 环境&#xff1a;jdk1.8 | mysql | maven | nodejs 二、代码及数据库 三、功能介绍 01. web端-首页1 02. web端-首页2 03. web端-注册 04. web端-登录 05. w…

“万万没想到”,“人工智能”获得2024年诺贝尔物理学奖

近日&#xff0c;2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者&#xff0c;这是历史上首次出现这样的情况。这项奖项原本只授予对自然现象和物质的物理学研究作出重大贡献的科学家&#xff0c;如今却将全球范围内对机器学习和神经网络的研究和开发作为了一种能…

SQLite Developer使用说明

1.SQLite Developer下载 SQLite Developer官方版是SharpPlus出品的一款数据库管理工具。支持对sqlite3数据库的管理&#xff0c;能够自动完成窗口显示和执行数据库命令等多种特色。并且支持打开.db文件&#xff0c;适用于Android的开发。另外&#xff0c;使用Sqlite Developer…

压缩包格式未知或损坏怎么办?四个简单修复步骤

压缩文件是我们日常工作中常用的工具&#xff0c;但有时在解压时会遇到提示“格式未知”或“压缩包已损坏”的情况。 这可能是由于下载不完整、文件传输错误、存储介质损坏等原因导致的。这种情况会影响到我们正常获取文件&#xff0c;尤其是当压缩包内含重要数据时更让人头疼…