java中成员变量的加载时机_工作奇谈——JAVA高级特性之反射

本文从面试问题出发,探讨了在Java中如何通过反射为私有成员变量赋值。介绍了Java反射机制的概念,包括类的加载过程(加载、连接、初始化)、类的加载时机以及类加载器的分类。同时,详细讲解了如何通过反射获取和操作类的构造方法、成员变量。最后,展示了获取和设置私有成员变量的示例代码。
摘要由CSDN通过智能技术生成

一、从问题入手

最近又要面试新人,所以翻了翻以前的代码,突然发现了一个有意思的问题。

问:如下一个Student类,请实例Student并对其成员变量赋值。

public class Student {

private String NAME;

private int AGE;

@Override

public String toString() {

return "Student [name=" + NAME + ", age=" + AGE + "]";

}

}

如果是个入行没多久或者基础不太好的初学者来看,肯定一脸蒙逼。两个私有成员变量set,get方法也没有,有参构造器也不提供,怎么搞?

其实也不难,首先看到这种只提供私有成员变量第一个想到的肯定是反射。代码如下:

public static void main(String[] args) throws Exception {

Class clazz = Student.class;

Object obj = clazz.newInstance();

Field fieldName = clazz.getDeclaredField("name");

Field fieldAge = clazz.getDeclaredField("age");

fieldName.setAccessible(true);

fieldAge.setAccessible(true);

fieldName.set(obj, "二十岁以后");

fieldAge.set(obj,21);

System.out.println(obj);

}

2c74e7279b478f7b12668bc64f8788df.png

那么什么是反射呢?

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

1.类的加载概述

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

(1)加载

就是指将class文件读入内存,并为之创建一个Class对象。

任何类被使用时系统都会建立一个Class对象。

(2)连接

1>验证 : 是否有正确的内部结构,并和其他类协调一致

2>准备 : 负责为类的静态成员分配内存,并设置默认初始化值

3>解析: 把类中的符号引用转换为直接引用

(3)初始化  就是类的初始化步骤

2.类的加载时机

(1)创建类的实例

访问类的静态变量,或者为静态变量赋值

(2)调用类的静态方法

使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

(3)初始化某个类的子类

直接使用java.exe命令来运行某个主类

3.类加载器的概述

负责将.class文件加载到内在中,并为之生成对应的Class对象。

4.类加载器的分类

Bootstrap ClassLoader 根类加载器

Extension ClassLoader 扩展类加载器

Sysetm ClassLoader     系统类加载器

5.类加载器的作用

(1)Bootstrap ClassLoader 根类加载器

也被称为引导类加载器,负责Java核心类的加载

比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

(2)Extension ClassLoader 扩展类加载器

负责JRE的扩展目录中jar包的加载。

在JDK中JRE的lib目录下ext目录

(3)Sysetm ClassLoader 系统类加载器

负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

/**

* 反射: 就是发生在运行状态下一种机制. 对于任意一个类我们可以获取到该类的字节码文件 对象 , 获取到

* 字节码文件对象以后,我们就可以剖析找个类

* java为我们的类中的每一种成员提供了对应的类对其进行描述:

*

* 成员变量 Field

* 构造方法 Constructor

* 成员方法 Method

*

* 获取一个类对应的字节码文件对象:

*

* (1): 通过调用getClass方法获取该类对应的字节码文件对象

* (2): 通过静态的class属性获取

* (3): 我们可以通过Class类中的一个静态方法叫做: forName(String className):

* public static Class> forName(String className)

*

*/

代码示例如下:通过三种方式去得的到Person类对应的字节码文件对象,以下输出结果都为True

fa41b04af35e9025761f626086350eb4.png

/*** 获取构造方法的方法

//获取所有公共的构造方法* public Constructor>[] getConstructors()

// 获取所有的构造方法,包括私有的* public Constructor>[] getDeclaredConstructors()

//获取带指定参数的共有构造方法* public Constructor getConstructor(Class... parameterTypes)  * public Constructor getDeclaredConstructor(Class>... parameterTypes)  */

代码示例为获取Student类的所有构造方法:

Student类:

193d599e726c90cc24606ea96e455e91.png

测试代码,获取Student类的三个构造方法

2201c9c4cb5b2de365dfbe41622600ee.png

输出为

4b56a7495336dee8d3b885bae8e84b83.png

测试代码,获取Student类参数为两个的公有构造器,并实例化对象

1a4aa1c538e292e9a8806b11a24dc18c.png

结果为:

9618a76be52f43c41969992faf328f94.png

通过反射获得类中的成员变量并使用

一共四个方法可以获取

getField(String name):获取单个成员变量,指定的成员变量对应的名称

getFields():获取的是所有公共的成员变量,包含从父类中继承过来的

getDeclaredFields():获取的是本类中所有的成员变量,包含私有的

getDeclaredField(String name):获取本类中指定成员变量

d321e636ced040aa812bdeb670034782.png

其中Student成员变量都为private且不提供Set、Get方法,且不通过两个参数的构造器实例化对象

b226443eb06c9b39ec031d9e013890f6.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值