概述:当程序要使用某个类的时候,如果该类还未被加载到内存中,则系统会通过以下三个步骤 ①类的加载 ②类的连接 ③类的初始化来对类进行初始化。如果不出现意外情况,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或者类初始化
类加载器的作用
概述:负责加载类的对象(java.lang包下)
方法:
方法 | 作用 |
---|---|
static ClassLoader getSystemClassLoader() | 返回用于委派的系统类加载器 |
ClassLoader getParent() | 返回父类加载器进行委派 |
名称 | 简述 |
---|---|
BootStrap ClassLoader | 它是虚拟机的内置类加载器,通常表示为null,并且没有父null |
Platform ClassLoader | 平台类加载器可以看到所有平台类,平台类包括由平台类加载器或其祖先定义的Java SE平台API,其实现类和JDK特定的运行时类 |
System ClassLoader | 它也被称为应用程序类加载器,与平台类加载器不同。系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具的类 |
概述:(框架设计的灵魂)将类的各个组成部分封装为其他对象(成员变量封装成Field对象),这就是反射机制
框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
反射的好处
注意:基本数据类型也可以通过.class得到对应的Class类型。私有的构造方法,成员方法,成员变量使用前,都需要暴力破解
方式一:Class.forName(“全类名”)
-在源代码(Source)阶段,将字节码(.class)文件加载进内存中,返回 类(Class)对象
-多用于配置文件,将类名定义在配置文件中。读取文件,加载类
// 例如:
Class s = Class.forName("cn.heng.Student");
方式二:类名.class
-在类(Class)对象阶段,通过类名的属性 class 获取
-多用于参数的传递
// 例如:
Class s = Student.class;
方式三:对象.getClass()
-在运行(Runtime)阶段,getClass()方法在Object类中定义着
-多用于对象的获取字节码的方式
// 例如:
Student t = new Student();
Class s = t.getClass();
注意:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的 Class 对象都是同一个
方法 | 概述 |
---|---|
Field[] getFields() | 获取所有public修饰的成员变量 |
Field getField(String name) | 获取指定名称的 public修饰的成员变量 |
Field[] getDeclaredFields() | 获取所有的成员变量,不考虑修饰符 |
Field getDeclaredField(String name) | 获取指定名称的成员变量,不考虑修饰符 |
设置值
void set(Object obj, Object value)
//成员变量.set( obj , value ) 给obj对象的此成员变量设置值为value
获取值
get(Object obj)
忽略访问权限修饰符的安全检查
setAccessible(true)
//暴力反射
方法名 | 概述 |
---|---|
Constructor<?>[] getConstructors() | 获取所有公共构造方法对象的数组 |
Constructor getConstructor(类<?>… parameterTypes) | 获取单个公共构造方法对象,参数是 类型.class |
Constructor getDeclaredConstructor(类<?>… parameterTypes) | 获取单个构造方法对象 |
Constructor<?>[] getDeclaredConstructors() | 获取所有构造方法对象的数组 |
创建对象
T newInstance(object...initars)
方法名 | 概述 |
---|---|
Method[] getMethods() | 获取所有公共成员方法的数组,包括继承 |
Method getMethod(String name, 类<?>… parameterTypes) | 获取单个指定方法名的公共成员方法对象 |
Method[] getDeclaredMethods() | 获取所有成员方法的数组,不包括继承 |
Method getDeclaredMethod(String name, 类<?>… parameterTypes) | 获取单个指定方法名的成员方法对象(包括私有) |
执行方法
Object invoke(Object obj, Object...args)
// 方法对象.invoke(obj,args) obj对象调用此方法,传递参数 args
获取方法名称
String getName()
反射如何实现访问私有(构造方法、成员方法、成员变量)?
Student t = new Student();
// 通过 全类路径获取 类对象
Class c = Class.forName("cn.depthLearn.classto.frame.Student");
// 通过 指定名称获取成员变量对象
Field f = c.getDeclaredField("age");
// 对象忽略检查
f.setAccessable(true);
// 获取值
Object age = f.get(t);
有一个 ArrayList 集合,我们想要往这个集合里添加字符串数据,如何实现?
//创建集合
ArrayList<Integer> array = new ArrayList<Integer>();
//获取array对象的类字节码对象
Class<? extends ArrayList> c = array.getClass();
//根据成员方法名,获取到成员方法对象
Method m = c.getDeclaredMethod("add", Object.class);
//array对象调用m(add)方法,传递参数
m.invoke(array,"张三");
m.invoke(array,"李四");
System.out.println(array);
我们通过字节码对象获取到添加方法对象,这样就越过泛型检查,获取原始方法所需要的参数类型(Object),我们就可以添加不同类型的数据在集合中。
案例分析
实现:
使用反射技术加载类文件进内存
配置文件
className=cn.depthLearn.classto.frame.Student
methodName=learn
Student 类,study 方法
public class Student {
private void learn(){
System.out.println( "要好好学习,天天向上哦");
}
}
框架反射实现
//创建Properties集合
Properties prop = new Properties();
//获取配置文件,这里我们使用类加载器获得配置文件
//获得类加载器
ClassLoader classLoader = FrameDemo.class.getClassLoader();
//获取class目录下的配置文件
InputStream is = classLoader.getResourceAsStream("pro.properties");
//将文件加载到集合中
prop.load(is);
//获取配置文件中定义的数据
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
//加载该类进内存
Class<?> c = Class.forName(className);
//创建对象
Object obj = c.newInstance();
//获取对象方法
Method method = c.getMethod(methodName);
//执行此方法
method.invoke(obj);