第十二章 类加载器&反射
12.1、类加载器
12.1.1、类加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载、类的连接、类的初始化这三个步骤来对类进行初始化。如果不出现意外情况,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或者类初始化
12.1.2、类初始化过程
- 类的加载
- 就是指将class文件读入内存,并为之创建一个java.lang.Class对象
- 任何类被使用时,系统都会为之建立一个java.lang.Class对象
- 类的连接
- 验证阶段:用于检验被加载的类是否有正确的内部结构并和其它类协调一致
- 准备阶段:负责为类的类变量分配内存并设置默认初始化值
- 解析阶段:将类的二进制数据中的符号引用替换为直接引用
- 类的初始化:在该阶段,主要就是对类变量进行初始化
- 假如类还未被加载和连接,则程序先加载并连接该类
- 假如该类的直接父类还未被初始化,则先初始化其直接父类
- 假如类中有初始化语句,则系统依次执行这些初始化语句
- 注意:在执行第2个步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1-3
12.1.3、类初始化时机
- 创建类的实例
- 调用类的方法
- 访问类、接口的变量或者为该类变量赋值
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
12.1.4、类加载器
概述:负责将.class文件加载到内存中并为之生成对应的 java.lang.Class 对象
Bootstrap class loader:它是虚拟机的内置类加载器,通常表示为null 并且没有父加载器
Platform class loader:它是平台类加载器,它可以看到所有平台类 :包括由平台类加载器或其祖先定义的Java SE平台API,其实现类和JDK特定的运行时类
System class loader:它是系统类加载器也被称为应用程序类加载器 ,与平台类加载器不同。 它通常用于定义应用程序类路径和JDK特定工具上的类
注意:类加载器的继承关系:System的父加载器为Platform,而Platform的父加载器为Bootstrap
12.1.5、类加载机制
全盘负责:当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
父类委托:当一个类加载器负责加载某个Class时,先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
缓存机制:保证所有加载过的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区中搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据并将其转换成 Class对象存储到缓存区
12.1.6、ClassLoader类
public class Demo {
public static void main(String[] args) {
ClassLoader c = ClassLoader.getSystemClassLoader();
System.out.println(c); // AppClassLoader
ClassLoader c2 = c.getParent();
System.out.println(c2); // PlatformClassLoader
ClassLoader c3 = c2.getParent();
System.out.println(c3); // null
}
}
12.2、反射
12.2.1、概述
反射是指在运行时去获取一个类的变量和方法信息,然后通过获取到的信息来创建对象,调用方法的一种机制。 由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展
12.2.2、获取Class类对象
class Student {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
// 方法1:使用类的class属性来获取该类对应的Class对象
Class<Student> c1 = Student.class;
System.out.println(c1);
// 方法2:调用对象的getClass()方法,返回该对象所属类对应的Class对象
Class<? extends Student> c2 = new Student().getClass();
System.out.println(c2);
// 方法3:使用Class类中的静态方法forName(String className)
Class<?> c3 = Class.forName("Student");
System.out.println(c3);
}
}
12.2.3、反射获取构造方法
方法描述:
| 方法 | 描述 |
|---|---|
| public Constructor<?>[] getConstructors() | 返回一个包含Constructor对象的数组,不包含私有构造 |
| public Constructor getConstructor(Class<?>... parameterTypes) | 返回一个指定的Constructor对象,不包含私有构造 |
| public Constructor<?>[] getDeclaredConstructors() | 返回一个包含Constructor对象的数组,包含私有构造 |
| public Constructor getConstructor(Class<?>... parameterTypes) | 返回一个指定的Constructor对象,包含私有构造 |
方法演示:
import java.lang.reflect.Constructor;
class Student {
// 成员变量:一个私有,一个默认,一个公共
private String name;
int age;
public String address;
// 构造方法:一个私有,一个默认,两个公共
private Student(String name) {
this.name = name;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
// 成员方法:两个私有,两个默认,两个公共
private String getName() {
System.out.println("getName");
return name;
}
private void setName(String name) {
System.out.println("setName:" + name);
this.name = name;
}
int getAge() {
System.out.println("getAge");
return age;
}
void setAge(int age) {
System.out.println("setAge:" + age);
this.age = age;
}
public String getAddress() {
System.out.println("getAddress");
return address;
}
public void setAddress(String address) {
System.out.println("setAddress:" + address);
this.address = address;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
public class Main {
public static void main(String[] args) throws Exception {
Class<Student> c = Student.class;
// 获取所有公开的构造方法
Constructor<?>[] constructors = c.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("--------------------");
// 获取指定参数且公开的构造方法
Constructor<Student> constructor = c.getConstructor(String.class, int.class, String.class);
System.out.println(constructor);
System.out.println("--------------------");
// 获取所有权限的构造方法
Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println("--------------------");
// 获取指定参数且不限的构造方法
Constructor<Student> declaredConstructor = c.getDeclaredConstructor(String.class);
System.out.println(declaredConstructor);
}
}
12.2.4、反射获取成员变量
方法描述:
| 方法 | 描述 |
|---|---|
| public Field[] getFields() | 返回一个包含Field对象的数组,不包含私有变量 |
| public Field getField(String name) | 返回一个指定的Field对象,不包含私有变量 |
| public Field[] getDeclaredFields() | 返回一个包含Field对象的数组,包含私有变量 |
| public Field getDeclaredField(String name) | 返回一个指定的Field对象,包含私有变量 |
方法演示:
import java.lang.reflect.Field;
class Student {
// 成员变量:一个私有,一个默认,一个公共
private String name;
int age;
public String address;
// 构造方法:一个私有,一个默认,两个公共
private Student(String name) {
this.name = name;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
// 成员方法:两个私有,两个默认,两个公共
private String getName() {
System.out.println("getName");
return name;
}
private void setName(String name) {
System.out.println("setName:" + name);
this.name = name;
}
int getAge() {
System.out.println("getAge");
return age;
}
void setAge(int age) {
System.out.println("setAge:" + age);
this.age = age;
}
public String getAddress() {
System.out.println("getAddress");
return address;
}
public void setAddress(String address) {
System.out.println("setAddress:" + address);
this.address = address;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
public class Main {
public static void main(String[] args) throws Exception {
Class<Student> c = Student.class;
// 获取所有公开的成员变量
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("--------------------");
// 获取指定名称且公开的成员变量
Field field = c.getField("address");
System.out.println(field);
System.out.println("--------------------");
// 获取所有权限的成员变量
Field[] declaredFields = c.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("--------------------");
// 获取指定名称且不限的成员变量
Field declaredField = c.getDeclaredField("name");
System.out.println(declaredField);
}
}
12.2.5、反射获取成员方法
方法概述:
| 方法 | 描述 |
|---|---|
| public Method[] getMethods() | 返回一个包含Method对象的数组,不包含私有成员方法 |
| public Method getMethod(String name, Class<?>... parameterTypes) | 返回一个指定的Method对象,不包含私有成员方法 |
| public Method[] getDeclaredMethods() | 返回一个包含Method对象的数组,包含私有成员方法 |
| public Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回一个指定的Method对象,包含私有成员方法 |
方法演示:
import java.lang.reflect.Method;
class Student {
// 成员变量:一个私有,一个默认,一个公共
private String name;
int age;
public String address;
// 构造方法:一个私有,一个默认,两个公共
private Student(String name) {
this.name = name;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
// 成员方法:两个私有,两个默认,两个公共
private String getName() {
System.out.println("getName");
return name;
}
private void setName(String name) {
System.out.println("setName:" + name);
this.name = name;
}
int getAge() {
System.out.println("getAge");
return age;
}
void setAge(int age) {
System.out.println("setAge:" + age);
this.age = age;
}
public String getAddress() {
System.out.println("getAddress");
return address;
}
public void setAddress(String address) {
System.out.println("setAddress:" + address);
this.address = address;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
public class Main {
public static void main(String[] args) throws Exception {
Class<Student> c = Student.class;
// 获取所有公开的成员方法,它反映此类或接口或从超类和超级接口继承的类的声明方法
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("--------------------");
// 获取指定参数且公开的成员方法,它反映此类或接口或从超类和超级接口继承的类的声明方法
Method method = c.getMethod("setAddress", String.class);
System.out.println(method);
System.out.println("--------------------");
// 获取所有权限的成员方法,它反映此类或接口的声明方法
Method[] declaredMethods = c.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("--------------------");
// 获取指定参数且不限的成员方法,它反映此类或接口的声明方法
Method declaredMethod = c.getDeclaredMethod("setName", String.class);
System.out.println(declaredMethod);
}
}
12.2.6、综合案例
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Student {
// 成员变量:一个私有,一个默认,一个公共
private String name;
int age;
public String address;
// 构造方法:一个私有,一个默认,两个公共
private Student(String name) {
this.name = name;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
// 成员方法:两个私有,两个默认,两个公共
private String getName() {
System.out.println("getName");
return name;
}
private void setName(String name) {
System.out.println("setName:" + name);
this.name = name;
}
int getAge() {
System.out.println("getAge");
return age;
}
void setAge(int age) {
System.out.println("setAge:" + age);
this.age = age;
}
public String getAddress() {
System.out.println("getAddress");
return address;
}
public void setAddress(String address) {
System.out.println("setAddress:" + address);
this.address = address;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
public class Main {
public static void main(String[] args) throws Exception {
// 获取学生类类对象
Class<Student> c = Student.class;
// 通过无参构造创建
Constructor<Student> constructor = c.getConstructor();
Student newStudent = constructor.newInstance();
System.out.println(newStudent);
System.out.println("--------------------");
// 反射设置成员变量
Field name = c.getDeclaredField("name");
name.setAccessible(true);
name.set(newStudent, "张三丰");
Field age = c.getDeclaredField("age");
age.setAccessible(true);
age.set(newStudent, 55);
Field address = c.getDeclaredField("address");
address.setAccessible(true);
address.set(newStudent, "武当山");
System.out.println(newStudent);
System.out.println("--------------------");
// 反射执行成员方法
Method getName = c.getDeclaredMethod("getName");
getName.setAccessible(true);
getName.invoke(newStudent);
Method setAge = c.getDeclaredMethod("setAge", int.class);
setAge.setAccessible(true);
setAge.invoke(newStudent, 60);
System.out.println(newStudent);
}
}
12.2.7、动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface UserDao {
public abstract void add();
public abstract void delete();
public abstract void update();
public abstract void find();
}
class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("添加功能");
}
@Override
public void delete() {
System.out.println("删除功能");
}
@Override
public void update() {
System.out.println("修改功能");
}
@Override
public void find() {
System.out.println("查找功能");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
Object result = method.invoke(target, args);
System.out.println("日志记录");
System.out.println();
return result;
}
}
public class Main {
public static void main(String[] args) throws Exception {
UserDao ud1 = new UserDaoImpl();
ud1.add();
ud1.delete();
ud1.update();
ud1.find();
System.out.println("----------");
UserDao ud2 = new UserDaoImpl();
MyInvocationHandler handler = new MyInvocationHandler(ud2);
UserDao ud2Proxy = (UserDao) Proxy.newProxyInstance(ud2.getClass().getClassLoader(), ud2.getClass().getInterfaces(), handler);
ud2Proxy.add();
ud2Proxy.delete();
ud2Proxy.update();
ud2Proxy.find();
}
}
第十二章 类加载器&反射的更多相关文章
- 深入了解java虚拟机(JVM) 第十二章 类加载器
一.什么是类加载器 类加载器是一个用来加载类文件的类,Java源代码通过javac编译器编译成类文件,然后JVM来执行类文件中的字节码来执行程序.需要注意的是,只有被同一个类加载器加载的类才可能会相等 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十二章:几何着色器(The Geometry Shader)
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十二章:几何着色器(The Geometry Shader) 代码工 ...
- JVM详解(二)-- 第2章 类加载器子系统
一.JVM内存结构 1.1 内存结构---概略图 1.2 内存结构--详细图 二.类加载器子系统的作用 类加载器子系统负责从文件系统或网络中加载.Class文件,文件需要有特定的标识(cafe bab ...
- 第十二章——SQLServer统计信息(3)——发现过期统计信息并处理
原文:第十二章--SQLServer统计信息(3)--发现过期统计信息并处理 前言: 统计信息是关于谓词中的数据分布的主要信息源,如果不知道具体的数据分布,优化器不能获得预估的数据集,从而不能统计需要 ...
- 第十二章——SQLServer统计信息(1)——创建和更新统计信息
原文:第十二章--SQLServer统计信息(1)--创建和更新统计信息 简介: 查询的统计信息: 目前为止,已经介绍了选择索引.维护索引.如果有合适的索引并实时更新统计信息,那么优化器会选择有用的索 ...
- 第十二章——SQLServer统计信息(2)——非索引键上统计信息的影响
原文:第十二章--SQLServer统计信息(2)--非索引键上统计信息的影响 前言: 索引对性能方面总是扮演着一个重要的角色,实际上,查询优化器首先检查谓词上的统计信息,然后才决定用什么索引.一般情 ...
- 《Django By Example》第十二章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第十二章,全书最后一章,终于到这章 ...
- 第二十二章 Django会话与表单验证
第二十二章 Django会话与表单验证 第一课 模板回顾 1.基本操作 def func(req): return render(req,'index.html',{'val':[1,2,3...]} ...
- Gradle 1.12用户指南翻译——第二十二章. 标准的 Gradle 插件
其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...
随机推荐
- .NET 开源工作流: Slickflow流程引擎高级开发(七)--消息队列(RabbitMQ)的集成使用
前言:工作流流程过程中,除了正常的人工审批类型的节点外,事件类型的节点处理也尤为重要.比如比较常见的事件类型的节点有:Timer/Message/Signal等.本文重点阐述消息类型的节点处理,以及实 ...
- 前端笔记(创建顺序数组、取选中月最后一天日期、判断变量、git命令)
创建一个从0开始的顺序数组 [...new Array(5).keys()] //[0,1,2,3,4] 数组反向 [0,1,2,3,4,5].reverse() //[4,3,2,1,0] 取选中月 ...
- Netty 源码解析(五): Netty 的线程池分析
今天是猿灯塔“365篇原创计划”第五篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel Netty ...
- Golang从合并链表聊递归
从合并链表聊递归 递归是工程师最常见的一种解决问题的方式,但是有时候不容易真正掌握.有人说是看起来很简单,自己写起来会费点劲. 最著名的例子就是斐波那契数列(Fibonacci sequence),通 ...
- 注册表写入自定义协议,网页打开exe
新建文件:Register.reg,写入代码: Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\exe1] @="exe1 P ...
- 洛谷 P1640 SCOI2010 连续攻击游戏 并查集
题目描述 lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备时,他只能使用该装备的某一个属性.并且每种装备 ...
- IA-32指令解析详解
IA-32指令解析详解 0x00 前言 这段时间忙于考试,信息论和最优化,还有算法分析,有点让人头大.期间花了几天看SEH机制,能明白个大概,但是对于VC++对于SHE的包装似乎还是不是很明白,发现逆 ...
- Java工具类之:包装类
Java工具类--包装类 我们都知道,JDK 其实给我们提供了很多很多 Java 开发者已经写好的现成的类,他们其实都可以理解成工具类,比如我们常见的集合类,日期相关的类,数学相关的类等等,有了这些工 ...
- smtp 发送邮件实例
发送邮件的关键点在于邮箱服务器地址是否一致 //smtp 服务器地址,咨询 smtp 提供商,例如 smtp.126.net 这种格式,端口和服务器地址是配套的,一般是 465 或者 25 SmtpC ...
- JVM 专题十三:运行时数据区(八)直接内存
1. 直接内存 不是虚拟机运行时数据区的一部分,也不是<Java虚拟机规范>中定义的内存区域. 直接内存是Java堆外的.直接向系统申请的内存区间. 来源于NIO,通过存在堆中的Direc ...