类加载器
类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
- 加载
就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。 - 连接
验证 : 是否有正确的内部结构,并和其他类协调一致
准备 : 负责为类的静态成员分配内存,并设置默认初始化值
解析: 把类中的符号引用转换为直接引用 - 初始化
就是通过无参构造或者有参构造创建对象并赋初始化值
类的加载时机:
- 创建类的实例
- 访问类的静态变量,或者为静态变量赋值
- 调用类的静态方法
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类 - 直接使用java.exe命令来运行某个主类
类加载器概述
负责将.class文件加载到内在中,并为之生成对应的Class对象。
-
分类
Bootstrap ClassLoader 根类加载器
Extension ClassLoader 扩展类加载器
Sysetm ClassLoader 系统类加载器 -
作用
Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载,比如System,String等。在JDK中JRE的lib目录下rt.jar文件中Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录Sysetm ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
反射
反射的概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性。
这种动态获取类的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。
而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。
- 获取class文件对象
获取class文件对象有三种方式:
- Object类的getClass()方法
public class MyReflect {
public static void main(String[] args) {
MyUtils myUtils = new MyUtils();
Class<? extends MyUtils> aClass = myUtils.getClass();
}
}
class MyUtils{}
- 静态属性class
public class MyReflect {
public static void main(String[] args) {
MyUtils myUtils = new MyUtils();
Class<MyUtils> myUtilsClass = MyUtils.class;
}
}
class MyUtils{}
- Class类中静态方法forName()
static 类<?> forName(String className)
public class MyReflect {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> aClass = Class.forName("org.Mydemo.MyUtils");
}
}
class MyUtils{}
通过反射获取构造方法并使用
- 获取构造方法的对象
方法 | 功能 |
---|---|
public Constructor<?>[] getConstructors() | 获取所有的构造方法不包含私有的 |
public Constructor<?>[] getDeclaredConstructors() | 获取所有的构造方法 包括私有的 |
public Constructor<T> getConstructor(Class<?>... parameterTypes) | 获取单个的构造方法 不包含私有的 |
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 获取单个的构造方法包含私有的 |
- 使用私有构造方法的对象创建该类对象
需要用到 Constructor 类,此类提供了一个类的单个构造方法的信息和访问。
方法 | 功能 |
---|---|
newInstance(Object... initargs) | 使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例 |
void setAccessible(boolean flag) | 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查,若为false则无法访问私有化目标反射的对象 |
public class MyConstructor {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> aClass = Class.forName("org.myDemo.Student");
Constructor<?> constructor = aClass.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
Object student = constructor.newInstance("张三", 23);
System.out.println(student);
}
}
class Student{
private String name;
private int age;
private Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
输出结果:
通过反射获取成员变量并使用
- 获取成员变量的对象
方法 | 功能 |
---|---|
public Field[] getFields() | 获取所有的成员变量包含从父类继承过来的 |
public Field[] getDeclaredFields() | 获取所有的成员变量 包含私有的 也包含从父类继承过来的成员变量 |
public Field getField(String name) | 获取单个的成员变量包含从父类继承过来的 |
public Field getDeclaredField(String name) | 获取单个的成员变量 包含私有的 也包含从父类继承过来的成员变量 |
- 使用私有成员变量的对象给私有变量赋值
需要用到 Field 类,此类提供有关类或接口的单个字段的信息和动态访问。
方法 | 功能 |
---|---|
Object get(Object obj) | 返回一个AnnotatedType对象,该对象表示使用类型来指定此Field所表示的字段的声明类型 |
void set(Object obj, Object value) | 将指定对象参数上的此 Field对象表示的字段设置为指定的新值 |
void setAccessible(boolean flag) | 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查,若为false则无法访问私有化目标反射的对象 |
public class MyField {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> aClass = Class.forName("org.MyDemo.Student");
Constructor<?> constructor = aClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object student = constructor.newInstance();
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
name.set(student,"张三");
Object o1 = name.get(student);
Field age = aClass.getDeclaredField("age");
age.setAccessible(true);
age.set(student,23);
Object o2 = age.get(student);
System.out.println(o1);
System.out.println(o2);
}
}
class Student{
private String name;
private int age;
private Student() {
}
}
- 输出结果:
通过反射获取成员方法并使用
- 获取成员方法的对象
方法 | 功能 |
---|---|
public Method[] getMethods() | 获取所有的公共的成员方法不包含私有的 包含从父类继承过来的过来的公共方法 |
public Method[] getDeclaredMethods() | 获取自己的所有成员方法 包含私有的 |
public Method getMethod(String name,Class<?>... parameterTypes) | 获取单个的方法 不包含私有的 |
public Method getDeclaredMethod(String name,Class<?>... parameterTypes) | 获取单个方法包括私有的 |
- 使用成员方法的对象让方法执行:
需要用到 Method 类,此类提供有关类和接口上单一方法的信息和访问权限。
方法 | 功能 |
---|---|
Object invoke(Object obj, Object... args) | 在具有指定参数的 方法对象上调用此 方法对象表示的底层方法 |
void setAccessible(boolean flag) | 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查,若为false则无法访问私有化目标反射的对象 |
public class MyMethod {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> aClass = Class.forName("org.MyDemo.Student");
Constructor<?> constructor = aClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object student = constructor.newInstance();
Method method1 = aClass.getDeclaredMethod("method1");
Object invoke1 = method1.invoke(student);
System.out.println(invoke1);
Method method2 = aClass.getDeclaredMethod("method2");
Object invoke2 = method2.invoke(student);
System.out.println(invoke2);
Method method3 = aClass.getDeclaredMethod("method3", String.class, int.class);
method3.setAccessible(true);
Object invoke3 = method3.invoke(student, "张三", 23);
System.out.println(invoke3);
}
}
class Student{
private Student() {
}
void method1(){
System.out.println("空参的公共方法执行了");
}
String method2(){
System.out.println("空参有返回值的方法执行了");
return "返回一个字符串";
}
private String method3(String name,int age){
System.out.println("有参又返回值的私有方法执行了");
return name+"今年"+age+"岁";
}
}
- 输出结果: