1. 类加载器
负责将.class文件(存储的物理文件)加载到内存中
1.1 类加载的过程
-
类加载时机
- 创建类的实例
- 调用类的类方法
- 访问类或者接口的类变量,或者为该类变量赋值
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
(有用到就加载,没用到就不加载)
-
类加载的过程
-
加载
- 通过包名 + 类名,获取这个类,准备用流进行传输
- 把这个类加载到内存中
- 加载完毕创建一个class对象
-
链接
-
验证
文件中的信心时候符合虚拟机规范,有没有安全隐患
-
准备
初始化静态变量
-
解析
本类中如果用到了其它类。此时就需要找到对应的类
-
-
初始化
根据程序员通过程序制定的主观计划去初始化类变量和其他资源
(静态变量赋值以及初始化其他资源)
-
1.2 类加载器的分类
- 分类
- Bootstrap class loader:虚拟机的内置类加载器,通常表示为null ,并且没有父null(启动类加载器—引导类加载器)
- Platform class loader:平台类加载器,负责加载JDK中一些特殊的模块(扩展类加载器)
- System class loader:系统类加载器,负责加载用户类路径上所指定的类库(应用程序类加载器)
1.3 双亲委派模型
-
介绍
如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
1.4 ClassLoader 中的两个方法
-
方法介绍
方法名 说明 public static ClassLoader getSystemClassLoader() 获取系统类加载器 public InputStream getResourceAsStream(String name) 加载某一个资源文件 -
注意
- getResourceAsStream(String name) :相对路径是在src下
2. 反射
在运行状态中,对于任意一个类都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意属性和方法;
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
2.1 获取Class类对象的三种方式
- 类名.class
- 对象名.getClass()方法
- Class.forName(全类名) 方法
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
//类名.class
Class clazz = Student.class;
System.out.println(clazz);//class com.lan.domain.Student
//对象名.getClass()方法
Student stu = new Student();
Class clazz1 = stu.getClass();
System.out.println(clazz1);//class com.lan.domain.Student
//Class.forName(全类名) 方法
Class clazz2 = Class.forName("com.lan.domain.Student");
System.out.println(clazz2);//class com.lan.domain.Student
//一个类只有一个类对象,是唯一的
System.out.println(clazz == clazz1);//true
System.out.println(clazz1 == clazz2);//true
}
}
2.2 反射获取构造方法并使用
-
Class类获取构造方法对象的方法
方法名 说明 Constructor<?>[] getConstructors() 返回所有公共构造方法对象的数组 Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组 Constructor getConstructor(Class<?>… parameterTypes) 返回单个公共构造方法对象 Constructor getDeclaredConstructor(Class<?>… parameterTypes) 返回单个构造方法对象 -
小栗子
public class Student { private String name; private Integer age; private String sex; public Student() { } private Student(String name, Integer age) { this.name = name; this.age = age; } public Student(String name, Integer age, String sex) { this.name = name; this.age = age; this.sex = sex; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}'; } 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 String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } //测试类 public class Test02 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { Class clazz = Class.forName("com.lan.domain.Student"); //返回所有公共构造方法对象的数组 Constructor[] constructors = clazz.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } //返回所有构造方法对象的数组,不管公有私有 Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); for (Constructor constructor : declaredConstructors) { System.out.println(constructor); } //返回无参构造的对象 Constructor clazzConstructor = clazz.getConstructor(); System.out.println(clazzConstructor); //返回有参构造的对象 Constructor clazzConstructor1 = clazz.getConstructor(String.class,Integer.class,String.class); System.out.println(clazzConstructor1); //返回私有有参构造的对象 Constructor clazzDeclaredConstructor = clazz.getDeclaredConstructor(String.class, Integer.class); System.out.println(clazzDeclaredConstructor); } }
-
Constructor类用于创建对象的方法
方法名 说明 T newInstance(Object…initargs) 根据指定的构造方法创建对象 setAccessible(boolean flag) 设置为true,表示取消访问检查
public class Test05 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取Class对象
Class clazz = Class.forName("com.lan.domain.Student");
//2. 获取构造方法对象
Constructor constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
//3.取消访问检查--暴力反射
constructor.setAccessible(true);
//4.创建对象
Student stu = (Student) constructor.newInstance("张三", 12);
System.out.println(stu);
//创建空参的简写格式
Student stu1 = (Student) clazz.newInstance();
System.out.println(stu1);
}
}
- 小结
2.3 反射获取成员变量并使用
-
Class类获取成员变量对象的方法
方法名 说明 Field[] getFields() 返回所有公共成员变量对象的数组 Field[] getDeclaredFields() 返回所有成员变量对象的数组 Field getField(String name) 返回单个公共成员变量对象 Field getDeclaredField(String name) 返回单个成员变量对象 -
小栗子
public class Test03 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class clazz = Class.forName("com.lan.domain.Student"); //返回所有公共成员变量对象的数组 Field[] fields = clazz.getFields(); for (Field field : fields) { System.out.println(field); } //返回所有成员变量对象的数组,包括私有 Field[] declaredFields = clazz.getDeclaredFields(); for (Field field : declaredFields) { System.out.println(field); } //返回单个公共成员变量对象 //获取的成员变量必须真实存在并且是public修饰的 //不然会出 NoSuchFieldException Field phone = clazz.getField("phone"); System.out.println(phone); //返回单个成员变量对象,包括私有也可以返回 Field name = clazz.getDeclaredField("name"); System.out.println(name); } }
-
Field类用于给成员变量赋值的方法
方法名 说明 void set(Object obj, Object value) 赋值 Object get(Object obj) 获取值 -
小栗子
public class Test04 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException { //1.获取Class对象 Class clazz = Class.forName("com.lan.domain.Student"); //2.获取name这个Field对象 Field fname = clazz.getDeclaredField("name"); //3.取消一下访问检查,暴力反射 fname.setAccessible(true); //4.创建对象 Student stu = (Student) clazz.newInstance(); //5.给指定对象赋值 fname.set(stu,"张三"); //6.获取指定对象的name值 System.out.println(fname.get(stu)); } }
2.4 反射获取成员方法并使用
-
Class类获取成员方法对象的方法
方法名 说明 Method[] getMethods() 返回所有公共成员方法对象的数组,包括继承的 Method[] getDeclaredMethods() 返回所有成员方法对象的数组,不包括继承的 Method getMethod(String name, Class<?>… parameterTypes) 返回单个公共成员方法对象 Method getDeclaredMethod(String name, Class<?>… parameterTypes) 返回单个成员方法对象 -
Method类用于执行方法的方法
方法名 说明 Object invoke(Object obj, Object… args) 运行方法 参数一: 用obj对象调用该方法
参数二: 调用方法的传递的参数(如果没有就不写)
返回值: 方法的返回值(如果没有就不写)
-
小栗子
public class Student { //私有的,有参有返回值 private String show(String name) { System.out.println("私有的show方法,有参有返回值,参数为:"+name); return "LAN"; } //公共的,无参无返回值 public void function1() { System.out.println("function1方法,无参无返回值"); } //公共的,有参无返回值 public void function2(String name) { System.out.println("function2方法,有参无返回值,参数为" + name); } //公共的,无参有返回值 public String function3() { System.out.println("function3方法,无参有返回值"); return "aaa"; } //公共的,有参有返回值 public String function4(String name) { System.out.println("function4方法,有参有返回值,参数为" + name); return "aaa"; } } public class Test06 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { //1.创建class对象 Class clazz = Class.forName("com.lan.test01.Student"); //2.获取成员方法 //返回所有公共方法,包括继承的 //method1(clazz); //返回所有成员方法,包括私有,不包括继承 //method2(clazz); //返回单个公共成员方法对象 //参数一:方法名 //参数二:可变参数,传入方法形参类型的class类 //method3(clazz); //返回单个成员方法对象,可以是私有 Method method = clazz.getDeclaredMethod("show", String.class); System.out.println(method); //运行方法 method.setAccessible(true); Student stu = (Student) clazz.newInstance(); Object invoke = method.invoke(stu, "张三"); System.out.println(invoke); } private static void method3(Class clazz) throws NoSuchMethodException { Method method = clazz.getMethod("function2", String.class); System.out.println(method); } private static void method2(Class clazz) { Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); } } private static void method1(Class clazz) { Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method); } } }