【Java】小白必须要懂的关于反射的极简基础知识

目录

反射概念

JVM基础

Class对象之源:类的加载过程

反射获取Class对象的三种方法

Class对象的三种常用方法

三种常用方法对应的后续调用

用反射来实现命令执行 


反射概念

反射(Reflection)是指在程序运行时可以检查、获取和修改类的属性、方法、构造函数等信息,以及在运行时创建对象、调用方法、访问属性等能力。Java 的反射机制提供了一组 API,使得我们可以在运行时动态操作类和对象,而不需要在编译时确定类的类型。

以下是反射机制的主要功能和用途:

  1. 获取类的信息:可以通过反射获取类的各种信息,如类名、父类、接口、字段、方法等。
  2. 创建对象:可以通过反射在运行时动态创建对象。
  3. 调用方法:可以通过反射在运行时调用对象的方法,包括私有方法。
  4. 访问和修改属性:可以通过反射在运行时访问和修改对象的属性,包括私有属性。
  5. 动态代理:可以使用反射生成动态代理对象,实现 AOP(面向切面编程)等功能。
  6. 实现工厂模式和配置文件解析:通过反射可以实现简单工厂模式、工厂方法模式以及解析配置文件来动态加载类。

反射机制的核心类是 java.lang.Class,它表示一个类的元数据信息。通过 Class 类的实例,可以获取类的各种信息,并对该类进行操作。常用的反射类还包括 java.lang.reflect.Methodjava.lang.reflect.Fieldjava.lang.reflect.Constructor 等,它们分别表示类的方法、字段和构造函数。

JVM基础

 

二进制字节码:类基本信息,常量池,类方法定义,包含了虚拟机指令

类放在方法区,类的实例化对象放在堆,对象调用方法在栈

Class对象之源:类的加载过程

而反射的核心,就是在类的加载这一步里在JVM堆(heap)中创建的Class对象,其指向方法区中的类元数据信息。

在Java虚拟机中,每个加载的类都会对应一个Class对象,这个Class对象保存了该类的结构信息,比如类的字段、方法、构造函数等。而这些类的结构信息实际上是保存在方法区中的。

同个类的多个实例化对象,共有一个Class对象

反射获取Class对象的三种方法

1.使用类名.class语法:在已知具体类的情况下,可以使用类字面常量的方式获取Class对象。例如,获取String类的Class对象可以使用String.class

Class<String> stringClass = String.class;

2.调用对象的getClass()方法:对于已经存在的对象,可以通过调用其getClass()方法获取对应的Class对象

String str = "Hello";
Class<? extends String> stringClass = str.getClass();

3.使用Class.forName()方法:当类的名称在编译时无法确定时,可以使用Class.forName()方法根据类的全限定名获取Class对象。该方法需要提供类的全限定名作为参数,并抛出ClassNotFoundException异常。

try {
    Class<?> stringClass = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

Class对象的三种常用方法

1.获取类的构造函数: getConstructors() 该方法返回一个包含当前类所有公共构造函数的数组。如果想要获取非公共构造函数,可以使用getDeclaredConstructors()方法。

import java.lang.reflect.Constructor;
public class Test {
    public static void main(String[] args) {
        Class<?> c = String.class;
        Constructor<?>[] constructors = c.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor.getName());
        }
    }
}

2.获取类的方法: getMethods() 该方法返回一个包含当前类以及其父类中所有公共方法的数组。如果想要获取非公共方法,可以使用getDeclaredMethods()方法。

import java.lang.reflect.Method;
public class Test {
    public static void main(String[] args) {
        Class<?> c = String.class;
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }
    }
}

3.获取类的属性: getFields() 该方法返回一个包含当前类以及其父类中所有公共属性的数组。如果想要获取非公共属性,可以使用getDeclaredFields()方法。

import java.lang.reflect.Field;
public class Test {
    public static void main(String[] args) {
        Class<?> c = String.class;
        Field[] fields = c.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
    }
}

三种常用方法对应的后续调用

一旦我们通过getConstructors()getMethods()getFields()方法获取了类的构造函数、方法和属性数组后,我们就可以通过这些数组中的元素来进一步操作和调用。

1.对构造函数的后续调用方法:
获取构造函数的参数类型:可以使用getParameters()方法获取构造函数的参数信息。
创建对象实例:通过构造函数对象可以使用newInstance(Object... initargs)方法来创建对象实例。

Constructor<?> constructor = constructors[0]; // 假设取第一个构造函数
Class<?>[] parameterTypes = constructor.getParameterTypes(); // 获取构造函数的参数类型
Object instance = constructor.newInstance("example"); // 通过构造函数创建对象实例

2. 对方法的后续调用方法:

调用方法:使用invoke(Object obj, Object... args)方法来调用方法,第一个参数是对象实例(静态方法可以传入null),后续参数是方法的实际参数。

Method method = methods[0]; // 假设取第一个方法
Object result = method.invoke(instance, "arg1", 123); // 调用方法并获取结果

3.对属性的后续调用方法:
获取和设置属性值:通过Field对象可以使用get(Object obj)和set(Object obj, Object value)方法来获取和设置属性值。

Field field = fields[0]; // 假设取第一个属性
Object value = field.get(instance); // 获取属性值
field.set(instance, "new value"); // 设置属性值

用反射来实现命令执行 

java.lang.Runtime

java.lang.Runtime的构造方法是私有的,但有一个公开方法getRuntime()来获取Runtime对象。

(在使用invoke(Object obj, Object... args)方法调用方法时,第一个参数obj表示要调用方法的对象实例。如果要调用的方法是静态方法(即不依赖于对象实例),则可以将该参数设置为null。)

Class clazz = Class.forName("java.lang.Runtime");
Object runTime = clazz.getMethod("getRuntime").invoke(null);
clazz.getMethod("exec", String.class).invoke(runTime, "calc");

也可以获取Runtime的私有构造器去构造Runtime对象

Class clazz = Class.forName("java.lang.Runtime");
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
clazz.getMethod("exec", String.class).invoke(constructor.newInstance(), "calc");

②java.lang.ProcessBuilder

ProcessBuilder.start()是另外一种命令执行的方式。

public ProcessBuilder(List command)

Class clazz = Class.forName("java.lang.ProcessBuilder");
clazz.getMethod("start").invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList("calc")));

public ProcessBuilder(String... command)  (String...和String[]等价) 

Class clazz = Class.forName("java.lang.ProcessBuilder");
clazz.getMethod("start").invoke(clazz.getConstructor(String[].class).newInstance(new String[][]{{"calc"}}));

(在调用 newInstance 的时候,因为这个函数本身接收的是一个可变长参数,我们传给
ProcessBuilder 的也是一个可变长参数,二者叠加为一个二维数组 )

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

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

相关文章

如何快速部署幻兽帕鲁私人服务器:适合零基础小白的指南

看了许多关于如何部署服务器的&#xff0c;大部分都是要买阿里云或者腾讯云的服务器并且至少四核以上才能保证流畅运行。 但是对于想搭建私服但又没有技术的小白&#xff0c;确实是有点难度了。购买云服务器后还要配置服务器&#xff0c;配置OpenVPN、PalServer&#xff0c;doc…

纯净住宅代理有何优势?为什么要用它?

随着互联网的快速发展&#xff0c;代理服务器已经成为许多在线活动的关键组成部分&#xff0c;从数据挖掘到网络安全。然而&#xff0c;随着技术的不断发展&#xff0c;住宅IP代理正崭露头角&#xff0c;因其在保障隐私、提升性能和应对封锁方面的卓越优势而备受瞩目。本文将深…

瑞_23种设计模式_代理模式

文章目录 1 代理模式&#xff08;Proxy Pattern&#xff09;1.1 介绍1.2 概述1.3 代理模式的结构 2 静态代理2.1 介绍2.2 案例——静态代理2.3 代码实现 3 JDK动态代理★★★3.1 介绍3.2 代码实现3.3 解析代理类3.3.1 思考3.3.2 使用 Arthas 解析代理类3.3.3 结论 3.4 动态代理…

常用的激活函数python代码-简洁版-想画好看的激活函数图的第一步

激活函数python代码 最近在写毕业论文&#xff0c;其中需要介绍一些基础的激活函数&#xff0c;然后如果直接用matplot绘图其绘图结果不是矢量图&#xff0c;而且不能像Origin一样修改线条&#xff0c;坐标轴之类的&#xff0c;但是如果像用Origin画就需要生成横纵坐标的数据然…

数据结构day1

定义一个学生结构体&#xff0c;包含结构体成员&#xff1a;身高&#xff0c;姓名&#xff0c;成绩&#xff1b;定义一个结构体数组有7个成员&#xff0c;要求终端输入结构体成员的值&#xff0c;根据学生成绩&#xff0c;进行冒泡排序。 #include <stdio.h> #include &l…

贪心算法之合并区间

“任世界多宽广&#xff0c;停泊在这港口~” 区间问题&#xff0c;涉及到最多的就是 取交集 和 并集的概念。我们使用C排序算法后&#xff0c;其默认规则就是按照 “左排序”进行的。因而&#xff0c;我们实质上注意的是每一个区间的 右端点&#xff0c;根据题目要求&#xff…

基于AI的RAG需要真正面对商业化场景和落地的几大致命陷井

背景 人人在谈AI&#xff0c;可是AI落地在哪&#xff1f;AI到底可以给我们带来什么&#xff1f; 随着流量红利模式的衰退、AI犹如一针强心剂一样打给了整个IT领域。 AI作图-漂亮、惊艳、快&#xff1b;AI视频-人人可以成为短视频专家&#xff1b;AI辅助编程-1人顶7人&#x…

安全基础~通用漏洞6

文章目录 知识补充XXE文件包含CTFshow闯关 知识补充 XML格式&#xff08;一种数据传输格式&#xff0c;现在被JSON取代&#xff09;&#xff1a;https://xz.aliyun.com/t/6887 XML文档结构包括XML声明、DTD文档类型定义&#xff08;可选&#xff09;、文档元素 DTD 定义合法的…

C++与C的区别

1、C不允许出现多个同名的全局变量 2、C中const修饰的变量可以通过指针修改 3、C语言&#xff1a;NULL&#xff0c;C中&#xff1a;nullptr C语言中NULL通常是0值&#xff0c;只报警告 C中nullptr的左值一定得是指针类型 4、C新增“引用” 引用&#xff1a;取别名 数据…

java常用应用程序编程接口(API)——Object类概述及常用方法

前言&#xff1a; Object是一个非常重要的语句&#xff0c;整理下心得。打好基础&#xff0c;daydayup! Object类 什么是Object类&#xff1f; Object类是java中所有类的最终类。每一个类都默认继承Object类&#xff0c;因此java中的所有类中的对象都可以直接使用Object类中提…

产品经理学习-产品运营《流程管理》

如何进行流程管理 信息可视化 甘特图-流程管理思维导图-方案讨论原型图-活动文档 明确责任制 分工明确&#xff0c;关键环境有主负责人通过时间倒推督促管理 沟通技巧 明确共同利益以结果激励做好信息同步 如何进行监控活动效果 监控活动的效果是要监控数据 活动每个环境的…

详解4大C语言内存函数【超详细建议点赞收藏】

目录 1. memcpy----内存拷贝1.1 函数介绍1.2 函数使用1.3 模拟实现 2. memmove----重叠内存的数据拷贝2.1 函数介绍2.2 函数使用2.3 模拟实现 3. memcmp----内存比较3.1 函数介绍3.2 函数使用 4.memset----内存设置4.1 函数介绍4.2 函数使用 注意&#xff1a;以下4个内存函数在…

Rocky Linux网卡静态配置

一、开源系统 Rocky Linux 下载安装 1、安装教程 Rocky Linux 下载安装 二、远程工具 MobaXterm下载安装 1、安装教程 MobaXterm 下载安装 三、Rocky Linux 网卡配置 1、使用ip addr确认网卡名称&#xff08;此处可得知网卡为ens160&#xff09; [rootlocalhost ~]# ip a 1:…

蓝桥杯每日一题----单调栈和单调队列

单调栈和单调队列 单调栈 单调栈即栈内的元素是单调递减或者单调递增的&#xff0c;我们通过一个题目来理解。 单调栈模板题 题目描述 给出项数为 n 的整数数列 a 1 … a n a_1…a_n a1​…an​。 定义函数 f ( i ) f(i) f(i)代表数列中第 i 个元素之后第一个大于 a i …

13.Qt 文件的读和写,样式表文件的读用

目录 前言&#xff1a; 技能&#xff1a; 内容&#xff1a; 1. 界面 2.信号槽 ①浏览按键 ②保存按键 ③加载样式按键 参考&#xff1a; 前言&#xff1a; 上一篇文章说明了如何弹窗选取文件并在Qlabel中显示文件内容 12.QT文件对话框 文件的弹窗选择-QFileDialog 这篇…

HTML 入门指南

简述 参考&#xff1a;HTML 教程- (HTML5 标准) HTML 语言的介绍、特点 HTML&#xff1a;超级文本标记语言&#xff08;HyperText Markup Language&#xff09; “超文本” 就是指页面内可以包含图片、链接等非文字内容。“标记” 就是使用标签的方法将需要的内容包括起来。…

星纪魅族宣布 All in AI;欧盟将首次对苹果处以罚款丨 RTE 开发者日报 Vol.146

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

世界顶级名校计算机专业,都在用哪些书当教材?(文末送书)

目录 01《深入理解计算机系统》02《算法导论》03《计算机程序的构造和解释》04《数据库系统概念》05《计算机组成与设计&#xff1a;硬件/软件接口》06《离散数学及其应用》07《组合数学》08《斯坦福算法博弈论二十讲》参与规则 清华、北大、MIT、CMU、斯坦福的学霸们在新学期里…

洛谷 P6546 [COCI2010-2011#2] PUŽ

讲解&#xff1a; 首先还是正常输入&#xff1a; int a,b,v; cin>>a>>b>>v; 然后经入一个函数num&#xff1a; cout<<num(1.0*(v-a),(a-b))1<<endl; 之所以要乘以1.0是因为要向上取整&#xff01;而这个num函数的两个参数则是“蜗牛白天爬了多…

python统计分析——一元线性回归分析

参考资料&#xff1a;用python动手学统计学 1、导入库 # 导入库 # 用于数值计算的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 用于绘图的库 import matplotlib.pyplot as plt import seaborn as sns sns.set() # 用于估计统计…