通俗易懂类加载机制

class Ade{
	private static Ade a = new Ade();
	public static int count1 = 0;
	public static int count2;
	private Ade(){
		count1++;
		count2++;
	}
	public static Ade getInstance(){
		return a;
	}
}
--------------------------------------------------------------

public class Test{
	public static void main(String[] args) {
		Ade a = Ade.getInstance();
		System.out.println("count1=="+a.count1);
		System.out.println("count2=="+a.count2);
	}
}

-------------------------------------------------------------------------------------

先以一道小题给大家琢磨一下上面代码执行后将会输出怎样的结果?

如果不了解类加载机制的朋友,可能琢磨了一会儿以后认为 输出:  count1==1    count2==1

然而,实际上结果为count1==0    count2==1

为什么会出现这样的结果呢?

让我们来了解一下类加载机制

       类加载的整个过程会经历 三大步(五小步)

1.加载

2.连接

2.1验证

2.2准备

2.3解析

3.初始化

首先咱们从第一步 加载 说起, 加载是类加载器把对应的class文件加载到jvm中来,如果想知道详细诸如双亲委派,可点击进入

我们这里要说的是:什么情况一个类会被加载进来呢?(有个小概念提一提,一个类如果被加载进来了不会再被加载)

①创建一个类的对象

②调用一个类的静态属性或静态方法

③加载一个子类之前会先把父类加载进来

④执行一个类的主函数

⑤反射

也就是说,上面题目中的例子:首先执行了Test的main方法,那么Test这个类先会被加载,然后由上至下执行main方法内容

Ade.getInstance(); 调用了Ade这个类的静态方法,那么Ade再被加载进来。

第二步是连接:

在这一步中有3小步,验证:验证做的事情是验证是否合法,那,为什么通过了编译器的验证还需要在进行加载的时候又验证一遍呢?

简单的可以这样理解,编译器生成的class文件,这个文件假如有黑客进行篡改后再放入java执行,那么如果加载的时候不再次验证

那么安全性很难保证

准备:准备阶段会把这个类中所有的静态的属性加载到方法区并给其赋予默认值,int类型的赋0,String类型的赋为null

也就是说上题中 在准备阶段时: Ade a=null; count1 = 0;count2=0

解析:解析阶段是把类、对象、字段进行解析,其实说简单点就是解析出谁对应谁,解析出这个变量对应的是哪个变量

比如一个变量 name,这个name到底是对应的局部变量的呢?还是对应全局变量的呢?

初始化:  初始化会把这个类中所有的静态的代码块从上至下依次执行(这里有个小概念:静态属性的等号的右边其实就是一个静态代码块)

什么意思呢?上题中在初始化时,会先执行 a = new Ade() ,这个时候 去构造方法中把count1和count2进行了++,接着这一行执行完毕后,

接着执行 count1 = 0; 把0的值再重新赋值给count1,而下面的count2并没有被重新赋值。

因此,最后的结果为:count1==0   ,    count2==1

如果还没搞懂的朋友,可以把下面两行代码调换下顺序

private static Ade a = new Ade();
public static int count1 = 0;
成为:
public static int count1 = 0;
private static Ade a = new Ade();
那么这样的话,结果会是count1和count2都是0,因为这样的话,初始化时
count1 = 0;先被执行了,而后再执行  a = new Ade();




<think>好的,用户想了解Java反射机制的基本概念和通俗解释。我需要结合提供的引用资料,用简单易懂的语言解释清楚。首先,反射机制的核心是动态获取信息和操作对象,这在框架设计中非常重要。要提到Class的作用,它是反射的起点,每个类加载后都会生成对应的Class对象。然后,可能需要比喻帮助理解,比如“X光机”或者“解剖”,让用户有直观印象。还要注意引用资料里的关键点,比如反射在运行时的状态,动态获取属性和方法的能力。要分步骤说明反射的基本使用流程,比如获取Class对象、实例化、调用方法等。最后,生成相关问题时要覆盖原理、应用场景、优缺点和实际例子。确保回答结构清晰,语言口语化,避免技术术语堆砌,让用户容易理解。</think>### Java反射机制的通俗解释 #### 一、核心概念 Java反射机制可以比喻为“**程序的自省能力**”——它允许代码在运行时像照镜子一样“观察”自身的结构,动态获取的信息并操作对象。例如,即使你不知道某个的具体定义,也能通过反射获取它的属性、方法和构造方法,甚至调用它们[^3][^4]。 #### 二、实现原理 反射的核心是`Class`。**每个加载到JVM时,都会自动生成一个唯一的`Class`对象**,这个对象包含的所有“元数据”(如方法、属性等)。通过这个对象,程序可以像“解剖”一样分析的内部结构[^2][^3]。 $$ \text{反射流程} = \text{获取Class对象} \rightarrow \text{解析信息} \rightarrow \text{动态调用} $$ #### 三、快速入门示例 1. **获取Class对象** ```java // 通过名获取 Class<?> clazz1 = String.class; // 通过对象获取 Class<?> clazz2 = "Hello".getClass(); // 通过全限定名动态加载 Class<?> clazz3 = Class.forName("java.lang.String"); ``` 2. **动态创建对象** ```java Class<?> clazz = Class.forName("com.example.User"); Object user = clazz.newInstance(); // 调用默认构造函数 ``` 3. **调用方法** ```java Method method = clazz.getMethod("setName", String.class); method.invoke(user, "Alice"); // 动态执行setName("Alice") ``` #### 四、核心价值 反射的典型应用场景是**框架设计**。例如: - **Spring框架**:通过反射动态创建Bean对象并注入依赖 - **MyBatis**:将数据库结果集映射到Java对象时使用反射赋值 - **JUnit**:通过反射识别并执行测试方法 正如引用所述:**“反射是框架设计的灵魂”**[^1][^3]。它让代码能灵活处理未知的结构,但也因破坏了封装性需谨慎使用。 --- ### 相关问题 1. 反射如何破坏封装性?使用时需注意哪些安全问题? 2. 通过反射获取私有方法时需要注意什么? 3. 反射与直接调用方法在性能上有何差异? 4. 能否举例说明反射在Spring框架中的具体应用场景? --- ### 引用说明 [^1]: 反射在框架中的核心地位及其抽象代码处理能力 : Class对象作为反射机制的起源与元数据载体 [^3]: 反射的动态特性与解剖能力 [^4]: 反射机制与程序自省能力的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值