一、反射基本概念
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
1.1 功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
二、Class类
- Class本身也是一个类
- Class 对象只能由系统建立对象
- 一个类在 JVM 中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.class文件
- 每个类的实例都会记得自己是由哪个 Class 实例所生成
- 通过Class可以完整地得到一个类中的完整结构
2.1 Object类中方法
public final Class getClass()
在Object类中定义了获取类的方法,此方法将被所有子类继承。
2.2 常用方式和反射方式对比
常用方式:
- 引入需要的“包类”名称
- 通过new实例化
- 取得实例化对象
反射方式:
- 实例化对象
- getClass()方法
- 得到完整的“包类”名称
2.3 实例化Class类对象方法
第一种:
Class clazz = String.class;
第二种:
Class clazz = “Hello”.getClass();
第三种:
Class clazz = Class.forName(“java.lang.String”);
第四种:
ClassLoader cl = this.getClass().getClassLoader();
Class clazz = cl.loadClass(“类的全类名”);
2.4 示例
@Test
public void fun5() throws ClassNotFoundException {
// 获取类模板对象的方法, 共有4种
// 1. 直接通过类.class, 效率最高最安全
Class clazz1 = Student.class;
// 2. 根据对象, 调用它的getClass() 方法获取,此方法也很常用
Student stu = new Student();
Class clazz2 = stu.getClass();
System.out.println(clazz1 == clazz2); // 常量池只使用一个类模板
// 3. 反射最常用的Class.forName("全类名");
Class clazz3 = Class.forName("com.javase.reflect.Student");
System.out.println(clazz2 == clazz3);
// 4. 通过类加载器对象动态加载类
ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz4 = classLoader.loadClass("com.javase.reflect.Student");
System.out.println(clazz3 == clazz4);
}
2.5 类的加载过程
- 类的加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成
- 类的连接:将类的二进制数据合并到JRE中
- 类的初始化:JVM负责对类进行初始化(执行静态语句块)
2.6 ClassLoader
类加载器是用来把类(class)装载进内存的。JVM 规范定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)。 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构
2.6.1 引导类加载器(Bootstap Classloader)
用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来加载核心类库。该加载器无法直接获取
2.6.2 扩展类加载器(Extension Classloader)
负责jre/lib/ext目录下的jar包或 –D java.ext.dirs 指定目录下的jar包装入工作库
2.6.3 系统类加载器(System Classloader)
负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工作 ,是最常用的加载器
2.7 双亲委派机制
- 类加载器收到类加载的请求;
- 把这个请求委托给父加载器去完成,一直向上委托,直到启动类加载器;
- 启动器加载器检查能不能加载(使用findClass()方法),能就加载(结束);否则,抛出异常,通知子加载器进行加载。
- 重复步骤三;
2.8 示例
//1.获取一个系统类加载器
ClassLoader classloader = ClassLoader.getSystemClassLoader();
System.out.println(classloader);
//2.获取系统类加载器的父类加载器,即扩展类加载器
classloader = classloader.getParent();
System.out.println(classloader);
//3.获取扩展类加载器的父类加载器,即引导类加载器
classloader = classloader