关于java的反射

❓❓❓反射是啥呀相信许多学java的同学非常困惑在学的时候,总是感觉懂了却又没懂或者直接忽略过去了,那么本文就带大家探讨一下什么是反射在java中以及它的机制和运用。

⭐️什么是反射:

首先我们知道一些知识:

维基百科的解释

在计算机学中,反射式编程(英语:reflective programming)或反射(英语:reflection),是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力.用比喻来说,反射就是程序在运行的时候能够"观察"并且修改自己的行为。

要注意术语"反射"和"内省"(type introspection)的关系。内省(或称"自省")机制仅指程序在运行时对自身信息(称为元数据)的检测;反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。

这个解释用在java就是通过jvm创建class示例进行操作反过来又能对对象进行访问和修改。反射(Reflection)是 Java 的一种特性,它可以让程序在运行时获取自身的信息,并且动态地操作类或对象的属性、方法和构造器等。通过反射功能,可以让我们在不知道具体类名的情况下,依然能够实例化对象,调用方法以及设置属性。

首先知道一个加载过程

Java语言的编译过程主要包括以下几个步骤:

词法分析:

词法分析器(Lexer)读取源代码文件,将源代码中的字符序列转换为记号(Token)序列。这些记号是编译器进一步处理的基本单元。

语法分析:

语法分析器(Parser)根据Java语言的语法规则,将词法分析器输出的记号序列组织成语法树(Abstract Syntax Tree, AST)。语法树表示了源代码中的程序结构。

语义分析:

语义分析器检查语法树是否满足语义规则,比如变量是否已经声明、类型是否匹配、表达式是否有意义等。这个阶段还会进行一些类型推断和转换。

字节码生成:

编译器将经过语义分析后的语法树转换成字节码(Bytecode)。字节码是一种平台无关的中间代码,它可以在任何安装了Java虚拟机(JVM)的平台上运行。

具体来说,Java编译过程如下:

源代码到字节码:

使用javac命令或Java编译器API将.java源文件编译成.class字节码文件。这一步包含了上述的词法分析、语法分析、语义分析和字节码生成。

字节码验证:

当.class文件被加载到JVM时,字节码验证器会检查字节码文件,确保其遵循Java语言规范,没有安全问题,比如确保不会发生数组越界、栈溢出等。

类加载:

类加载器(ClassLoader)负责将.class文件加载到JVM中,并为字节码分配内存,将其转换为运行时数据结构。

运行时优化:

JVM可能会对字节码进行即时编译(Just-In-Time, JIT)优化,将字节码转换成本地机器码以提高执行效率。

执行:

最终,在JVM上执行这些字节码,程序开始运行。

这个过程确保了Java语言的"一次编写,到处运行"的特性,因为编译生成的字节码可以在任何有JVM的平台上执行。

然后我们正式开始:

反射之中包含了一个「反」字,所以想要解释反射就必须先从「正」开始解释。

一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。

c 复制代码
Apple apple = new Apple(); //直接初始化,「正射」
apple.setPrice(4);

上面这样子进行类对象的初始化,我们可以理解为「正」。

而反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。

这时候,我们使用 JDK 提供的反射 API 进行反射调用:

c 复制代码
Class clz = Class.forName("com.muggle.reflect.Apple");
Method method = clz.getMethod("setPrice", int.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, 4);

上面两段代码的执行结果,其实是完全一样的。但是其思路完全不一样,第一段代码在未运行时就已经确定了要运行的类(Apple),而第二段代码则是在运行时通过字符串值才得知要运行的类(com.chenshuyi.reflect.Apple)。

所以说什么是反射?

反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

⭐️获取Class对象的三种方式

java 复制代码
package fanshe;
/**
 * 获取Class对象的三种方式
 * 1 Object ------> getClass();
 * 2 任何数据类型(包括基本数据类型)都有一个"静态"的class属性
 * 3 通过Class类的静态方法:forName(String  className)(常用)
 *
 */
public class Fanshe {
	public static void main(String[] args) {
		//第一种方式获取Class对象  
		Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
		Class stuClass = stu1.getClass();//获取Class对象
		System.out.println(stuClass.getName());
		
		//第二种方式获取Class对象
		Class stuClass2 = Student.class;
		System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
		
		//第三种方式获取Class对象
		try {
			Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
			System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
}

⭐️反射的运用

框架:半成品软件。可以在框架的基础上进行软件开发,简化编码

反射:将类的各个组成部分封装为其他对象,这就是反射机制

​ 好处:

​ 可以在程序运行过程中,操作这些对象。

​ 可以解耦,提高程序的可扩展性。

像咱们平时大部分时候都是在写业务代码,很少会接触到直接使用反射机制的场景。但是,这并不代表反射没有用。相反,正是因为反射,你才能这么轻松地使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。比如下面是通过 JDK 实现动态代理的示例代码,其中就使用了反射类 Method 来调用指定的方法。

java 复制代码
public class DebugInvocationHandler implements InvocationHandler {
    /**
     * 代理类中的真实对象
     */
    private final Object target;

    public DebugInvocationHandler(Object target) {
        this.target = target;
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        System.out.println("before method " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("after method " + method.getName());
        return result;
    }
}

另外,像 Java 中的一大利器 注解 的实现也用到了反射。为什么你使用 Spring 的时候 ,一个@Component注解就声明了一个类为 Spring Bean 呢?为什么你通过一个 @Value注解就读取到配置文件中的值呢?究竟是怎么起作用的呢?这些都是因为你可以基于反射分析类,然后获取到类/属性/方法/方法的参数上的注解。你获取到注解之后,就可以做进一步的处理。谈谈反射机制的优缺点优点:可以让咱们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利缺点:让我们在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。

在使用 JDBC 连接数据库时使用 Class.forName()通过反射加载数据库的驱动程序,如果是mysql则传入mysql的驱动类,而如果是oracle则传入的参数就变成另一个了。

Spring 框架的 IOC(动态加载管理 Bean),Spring通过配置文件配置各种各样的bean,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载,你的程序就能健壮地运行。

还有Spring AOP(动态代理)功能都和反射有关系。

除此之外还有很多框架:mybatis、dubbo、rocketmq等等都会用到反射机制。


参考

反射的作用
大白话说反射

javaguide
java非常重要的基础概念之一
反射

相关推荐
芊寻(嵌入式)13 分钟前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
WaaTong14 分钟前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
m0_7430484414 分钟前
初识Java EE和Spring Boot
java·java-ee
AskHarries16 分钟前
Java字节码增强库ByteBuddy
java·后端
一颗松鼠21 分钟前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
有梦想的咸鱼_23 分钟前
go实现并发安全hashtable 拉链法
开发语言·golang·哈希算法
海阔天空_201329 分钟前
Python pyautogui库:自动化操作的强大工具
运维·开发语言·python·青少年编程·自动化
天下皆白_唯我独黑36 分钟前
php 使用qrcode制作二维码图片
开发语言·php
小灰灰__36 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
零意@37 分钟前
ubuntu切换不同版本的python
windows·python·ubuntu