Java反射原理简析

article/2025/9/21 3:39:03

Java的反射机制允许我们动态的调用某个对象的方法/构造函数,获取某个对象的属性等,而无需在编码时确定调用的对象。这种机制在我们常用的框架中也非常常见。

1.原理简介

类actionClass = Class.forName(“ MyClass”);
对象action = actionClass.newInstance();
方法method = actionClass.getMethod(“ myMethod”,null);
method.invoke(action,null);

上面就是最常见的反射使用的例子,前两行实现了类的装载,链接和初始化(newInstance方法实际上也是使用反射调用了方法),后两行实现了从类对象中获取到方法对象然后执行反射调用。下面简单分析一下后两行的原理。

其实我们预言,上面的代码中,如果想要实现method.invoke(action,null)调用action对象的myMethod方法,只需要实现这样一个方法类即可:

类方法{公共对象invoke(Object obj,Object [] param){MyClass myClass =(MyClass)obj;返回myClass.myMethod();}}

反射的原理之一其实就是动态的生成上述的字节码,加载到jvm中运行。

2.获取方法对象

首先来看一下方法对象是如何生成的:

在这里插入图片描述

上面的类对象是在加载类时由JVM结构的,JVM为每个类管理一个独一无二的类对象,此类对象里维护着该该类的所有方法,字段,构造函数的缓存,这份缓存也可以被get根对象。每次getMethod获取到的方法对象都持有对根对象的引用,因为一些重量级的Method的成员变量(主要是MethodAccessor),我们不希望每次创建方法对象都要重新初始化,于是所有代表同一个方法的方法对象都共享着根对象的MethodAccessor,每一次创建都会调用根对象的副本方法复制一份:

方法copy(){ 方法res =新方法(clazz,名称,parameterTypes,returnType,exceptionTypes,修饰符,广告位,签名,注释,parameterAnnotations,annotationDefault);res.root =这个;res.methodAccessor = methodAccessor;返回资源;}

3.调用invoke()方法

获取到方法对象之后,调用invoke方法的流程如下:

在这里插入图片描述
可以看到,调用Method.invoke之后,会直接去调MethodAccessor.invoke。MethodAccessor就是上面提到的所有同名方法共享的一个实例,由ReflectionFactory创建。 4之后):如果该方法的累积调用次数<= 15,会创建出NativeMethodAccessorImpl,它的实现就是直接调用nativeMethod实现反射;如果该方法的累计调用次数> 15,会由java代码创建出字节码(是否采用inflation和15个数字都可以在jvm参数中调整)
以调用MyClass.myMethod(String s)为例,生成出的MethodAccessorImpl字节码翻译成Java代码大致如下:

公共类GeneratedMethodAccessor1扩展了MethodAccessorImpl {    公共对象invoke(Object obj,Object [] args)引发异常{尝试{MyClass目标=(MyClass)obj;字符串arg0 =(String)args [0];target.myMethod(arg0);} catch(Throwable t){抛出新的InvocationTargetException(t);}}
}

这样的native方法的实现,由于比较深入此处就不探讨了,欢迎有兴趣的同学来补充。

4.性能

下面分析一下反射的性能相关的问题,以及为什么要有通货膨胀这个机制。下图是我本地循环使用反射二十次的耗时(单位ns):
在这里插入图片描述
从变化趋势上看,第1次和第16次调用是最耗时的(初始化NativeMethodAccessorImpl和字节码拼装MethodAccessorImpl)。然后初始化是替代的,而native方式的初始化会替代,因此前一次的调用会采用native方法。
随着调用次数的增加,每次反射都使用JNI跨越nativenative边界变量优化有干扰作用,相对来说使用拼写装出的字节码可以直接以Java调用的形式实现反射,发挥了JIT优化的作用,避免了JNI为了维护OopMap(HotSpot实现实现准确式GC的数据结构)进行封装/解压缩封装的性能提高。因此在已经创建了MethodAccessor的情况下,使用Java版本的实现会因此当调用次数到达一定次数(15次)后,会切换成Java实现的版本,来优化未来可能的更交替的反射调用。

以上就是本次对反射的分享学习,推荐文章R大的博文http://rednaxelafx.iteye.com/blog/548536,和代码相关的细节在介绍文章里写得比较多,笔者也是在这篇文章基础上进行学习探究的。


http://chatgpt.dhexx.cn/article/Tag7Mf9C.shtml

相关文章

java反射原理

一、反射机制 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态(在运行时)获取类的信息以及动态调用对象的方法的功能称为java语言的反射机制。简单来说,就是Java对每一个类和类中的所有成…

Java反射(原理剖析与使用)

一、反射机制是什么 1、Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息&#xff0c;从而操作类或对象的属性和方法。本质是JVM得到class对象之后&#xff0c;再通过class对象进行反编译&#xff0c;从而获取对象的各种信息。 2、Java属于先编译再运行的语言&a…

java反射机制原理详解

Java反射机制是指在运行时动态地获取一个类的信息并能够操作该类的属性和方法的能力。Java反射机制使得程序能够在运行时借助Class类的API来操作自身的属性和方法&#xff0c;从而大大增强了Java的灵活性和可扩展性。本文将详细介绍Java反射机制的原理以及如何使用它。 1、反射…

Java 反射及原理

反射&#xff0c;指的是对于任意一个类&#xff0c;都可以动态的获得它的所有属性和方法&#xff0c;对于任意一个对象都能调用的它的所有属性和方法&#xff0c;都能够调用它的任意方法和属性&#xff1b;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。…

回车、换行、回车换行、硬回车以及软回车

回车、换行、回车换行、硬回车以及软回车 要想一句话说清楚它们之间的关系&#xff0c;不太简单。但认真看完后&#xff0c;会发现它们之间的关系其实也挺简单的。 回车、换行与回车换行 英文缩写对应按键英文全称中文名称解释转义表达式使用平台CRreturnCarriage Return回车…

图解回车和换行的区别

文章目录 1. 定义2. 图解3. 讨论4. 结论 1. 定义 中文英文简写HEXCharacterASCII回车Carriage returnCR0x0D\r13换行Line feedLF0x0A\n10 2. 图解 Win11 Experiment by Pycharm with Python 3.9 print(---)print(Hello World)print(---)# \rprint(Hello \r World)print(---…

不同系统下回车和换行的区别

在计算机还没有出现之前&#xff0c;有一种叫做电传打字机&#xff08;Teletype Model 33&#xff09;的玩意&#xff0c;每秒钟可以打10个字符。但是它有一个问题&#xff0c;就是打完一行换行的时候&#xff0c;要用去0.2秒&#xff0c;正好可以打两个字符。要是在这0.2秒里面…

python回车和换行的区别_回车与换行的区别(转)

add by zhj: 不同操作系统下换行符不同&#xff0c;如下&#xff1a; \n: UNIX \n\r: window \r: MAC OS 我们经常遇到的一个问题就是&#xff0c;Unix/Mac系统下的文件在Windows里打开的话&#xff0c;所有文字会变成一行&#xff1b;而Windows里的文件在Unix/Mac下打开的…

回车与换行的区别,CRLF、CR、LF详解(\r \n \r\n的区别)

先上结论 缩写ASCⅡ转义系统ASCⅡ值CR\rMacIntosh&#xff08;早期的Mac&#xff09;13LF\nUnix/Linux/Mac OS X10CR LF\r\nWindows 很长一段时间里&#xff0c;对于CRLF、CR、LF的理解仅限于不同操作系统下对换行符的定义。所谓知其然需知其所以然&#xff0c;从学习中找到乐…

回车符,换行符的区别

首先介绍一下“回车”&#xff08;carriage return,’\r’&#xff09;和“换行”&#xff08;line feed,’\n’&#xff09;这两个概念的来历和区别。在计算机还没有出现之前&#xff0c;有一种叫做电传打字机&#xff08;Teletype Model 33&#xff09;的玩意&#xff0c;每秒…

换行和回车的区别

我们在看他们的区别时我们先看看他们的分别指的是什么&#xff1a; 回车<\r>(carriage return)&#xff1a;告诉打印机把打印头定位到左边界&#xff0c;就是指的&#xff0c;那个打印头重新放在这一行的开始。 换行<\n>(line feed)&#xff1a;告诉打印机把打印头…

回车符和 换行符的区别

首先介绍一下“回车”&#xff08;carriage return,’\r’&#xff09;和“换行”&#xff08;line feed,’\n’&#xff09;这两个概念的来历和区别。在计算机还没有出现之前&#xff0c;有一种叫做电传打字机&#xff08;Teletype Model 33&#xff09;的玩意&#xff0c;每秒…

回车符、换行符和回车换行符

我的CSDN主页My Python 学习个人备忘录我的HOT博 自学并不是什么神秘的东西&#xff0c;一个人一辈子自学的时间总是比在学校学习的时间长&#xff0c;没有老师的时候总是比有老师的时候多。             ——华罗庚 \r 、\n 和 \r\n 题目代码运行效果我的解题思路…

回车符与换行符的区别

引用了博客&#xff1a;https://blog.csdn.net/fanwenbo/article/details/54848429 这里是我自己做的实验&#xff0c;如下&#xff1a; printf("A is here!");printf("I am here!");putchar(\r);printf("First input!");putchar(\n);printf(&qu…

“回车”、“换行”浅谈

“回车”、“换行”浅谈 转义字符\r表示回车&#xff08;carriage return&#xff09;即回到行首&#xff0c;并没有包含换行的动作&#xff0c; \n表示换行&#xff08;line feed&#xff09;即移动到新的一行&#xff08;下一行&#xff09;。顺便提及&#xff0c;\b表示退格…

回车与换行符的区别及python中使用

一、区别 转载自http://www.pythontab.com/html/2017/linuxkaiyuan_0115/1116.html 1. 由来 在计算机还没有出现之前&#xff0c;有一种叫做电传打字机&#xff08;Teletype Model 33&#xff09;的机械打字机&#xff0c;每秒钟可以打10个字符。但是它有一个问题&#xff0c…

回车和换行的区别

回车和换行的区别 回车和换行的概念不同的系统间传递文件会涉及格式的转换Unix -> WindowsUnix <- Windows 回车和换行的概念 首先介绍一下“回车”&#xff08;carriage return,’\r’&#xff09;和“换行”&#xff08;line feed,’\n’&#xff09;这两个概念的来历…

在数组中查找指定元素 (15分)

int search( int list[], int n, int x ){int index -1;for(int i0;i<n;i){if(list[i] x){index i;break;}}return index; }

[PTA]习题8-2 在数组中查找指定元素

Spring-_-Bear 的 CSDN 博客导航 本题要求实现一个在数组中查找指定元素的简单函数。 函数接口定义&#xff1a; int search( int list[], int n, int x );其中 list[] 是用户传入的数组&#xff1b;n&#xff08;≥0&#xff09;是 list[] 中元素的个数&#xff1b;x 是待查…

[PTA]实验8-1-5 在数组中查找指定元素

Spring-_-Bear 的 CSDN 博客导航 本题要求实现一个在数组中查找指定元素的简单函数。 函数接口定义&#xff1a; int search( int list[], int n, int x );其中 list[] 是用户传入的数组&#xff1b;n&#xff08;≥ 0&#xff09;是 list[] 中元素的个数&#xff1b;x 是待…