文章目录
- 一.java程序编译运行过程
-
-
- [1. Java源代码](#1. Java源代码)
- [2. 编译器](#2. 编译器)
- [3. JVM可执行的字节码](#3. JVM可执行的字节码)
- [4. JVM中的解释器](#4. JVM中的解释器)
- [5. 机器可执行的二进制机器码](#5. 机器可执行的二进制机器码)
- [6. 程序运行](#6. 程序运行)
-
- 二.什么是反射
- 三.反射的使用
-
-
- [1. 获取Class对象](#1. 获取Class对象)
- [2. 创建对象实例](#2. 创建对象实例)
- [3. 访问字段](#3. 访问字段)
- [4. 调用方法](#4. 调用方法)
- [5. 操作数组](#5. 操作数组)
-
一.java程序编译运行过程
java源代码 - - - 编译器 - - - jvm可执行的字节码 - - - jvm中的解释器 - - - 机器可执行的二进制机器码 - - - 程序运行
1. Java源代码
- 编写 :开发者使用Java语言编写源代码,保存在以
.java
为扩展名的文件中。
2. 编译器
- 编译 :Java编译器(如
javac
)将.java
文件中的源代码编译成Java字节码。这一步涉及语法分析、语义检查、生成中间表示和最后生成字节码。 - 输出 :编译器生成的输出是
.class
文件,其中包含与源代码对应的字节码。
3. JVM可执行的字节码
- 字节码:字节码是一种介于源代码和机器码之间的中间形式,设计为可以在任何实现了Java虚拟机的平台上运行。
4. JVM中的解释器
- 加载 :当运行Java程序时,JVM的类加载器负责将
.class
文件加载到内存中。 - 连接:在连接阶段,JVM执行验证、准备和解析步骤,确保代码的安全性和正确性。
- 初始化:在此阶段,JVM处理静态变量和静态块,执行类构造器。
5. 机器可执行的二进制机器码
- 解释执行:JVM的解释器逐条解释执行字节码,将其翻译成可以在特定硬件上执行的机器指令。这是一个逐步的过程,每次解释一条字节码指令。
- 即时编译(JIT编译):为了提高性能,热点代码(即执行次数较多的代码)会被JVM中的即时编译器编译成本地机器码,这样可以直接由硬件执行,无需再进行逐条解释,从而提高执行效率。
6. 程序运行
- 执行:经过上述所有转换和处理后,程序最终在计算机硬件上运行,用户可以看到程序执行结果。
二.什么是反射
官方定义: 反射(Reflection)是一个强大的机制,它允许程序在运行时查询和操作对象的类信息。使用反射API,可以动态地创建对象、调用方法、访问字段(即便它们被定义为私有的),并且能够加载类。
1.反射与字节码的关系
字节码是java源代码经过javac编译器编译后的中间文件表现形式,即.class里面的内容,这些字节码可以当作jvm的执行的指令集。
而反射是一种在运行时检查或修改程序行为的机制。它以字节码为基础,就是它会首先创建一个Class对象,这个对象能够从字节码中读取类信息,即构造函数,方法,字段这些,私有的也可以访问到
,所以具有动态操作
的优点和破坏封装性
的缺点.
2.Class对象工作流程
-
类加载 :JVM首次引用某个类时,它将加载该类的字节码,解析字节码中的元数据,并为这个类创建一个
Class
类型的对象。 -
信息访问 :通过这个
Class
对象,可以访问类的各种信息:- 获取字段(Field):可以检索类中声明的所有字段,无论它们的访问权限如何。
- 获取方法(Method):可以获取类定义的所有方法。
- 获取构造器(Constructor):可以访问类的所有构造方法。
- 获取超类和接口:可以查看类的父类和实现的接口。
-
创建实例 :可以使用
Class
对象来创建其表示的类的实例。这通常通过调用newInstance()
方法实现,或者通过获取适当的构造器对象并调用其newInstance()
方法。 -
动态操作:可以动态调用方法或访问字段,这在编译时是未知的,所以不需要指定特殊类。
三.反射的使用
1. 获取Class对象
java
Class<?> clazz1 = Class.forName("java.util.ArrayList"); // 通过类的全限定名
Class<?> clazz2 = ArrayList.class; // 通过类字面量
ArrayList<String> arrayList = new ArrayList<>();
Class<?> clazz3 = arrayList.getClass(); // 通过对象实例调用getClass()
2. 创建对象实例
java
Class<?> clazz = Class.forName("java.util.ArrayList");
Object arrayList = clazz.getDeclaredConstructor().newInstance(); // 创建对象实例
3. 访问字段
java
Class<?> clazz = Class.forName("com.example.MyClass");
Field field = clazz.getDeclaredField("myField"); // 获取指定字段
field.setAccessible(true); // 设置可访问性,对于私有字段非常重要
Object fieldValue = field.get(instance); // 读取字段值
field.set(instance, "new value"); // 设置新的字段值
4. 调用方法
java
Class<?> clazz = Class.forName("com.example.MyClass");
Method method = clazz.getDeclaredMethod("myMethod", String.class); // 获取方法
method.setAccessible(true); // 对于私有方法必须这么做
Object result = method.invoke(instance, "parameter"); // 调用方法
5. 操作数组
java
int[] intArray = (int[]) Array.newInstance(int.class, 3); // 创建一个整型数组
Array.set(intArray, 0, 123); // 设置数组元素
int value = Array.getInt(intArray, 0); // 获取数组元素