类加载器
日常程序员在编写代码时,编写的是java文件,但实际上jvm虚拟机运行的是时编译后的字节码文件。而字节码文件从我们本地硬盘加载到jvm虚拟机的这个过程,称之为类加载。
而加载字节码文件到虚拟机这个过程是由类加载器完成的。
类加载时机
- 创建一个类的实例(对象)
- 调用类的类方法(静态方法)
- 访问类或者接口的类变量(静态变量),或者为该类变量赋值
- 反射强制创建某个类或者接口对应的class对象
- 初始化某个类的子类
- 直接使用java.exe命令运行某个主类
总结:
用到就加载,不用不加载
类加载过程
加载
- 通过一个类的全限定名来获取定义此类的二进制字节流
通过包名+类名,获取这个类,准备用流进行传输
- 将者字节流所代表的静态存储结构转化为运行时数据结构
将这个类加载到内存中
- 在内存中生成一个代表这个类的java.lang.Class对象
加载完毕创建一个class对象
- 任何类被使用时,系统都会为之创建一个java.lang.Class对象
示意图:
验证
- 链接阶段的第一步,这一阶段为了确保Class文件字节流中
- 包含的信息符合虚拟机的要求,并且不会危害虚拟机的自身安全
文件中的信息是否符合虚拟机规范,有没有安全隐患
准备
- 负责为类的类变量(被static修饰的变量分配内存),并设置默认初始化值
初始化静态变量
解析
- 将类的二进制数据流中的符号引用替换为直接引用
本类中如果用到了其他类,此时需要找到对应的类
eg:
如果有一个String类型的name,那么这个阶段需要找到String这个类的引用地址,
并指向我们原本代替的临时符号。
初始化
- 根据程序员通过程序制定的主观计划去初始化类变量和其他资源(静态变量赋值以及初始化其他资源)
类加载器分类
- 启动类加载器(BootstrapClassLoader):虚拟机内置的类加载器
底层是用c++语言实现,当jvm启动的时候,会自动进行启动
- 平台类加载器(PlatformClassLoader):负责加载JDK中的一些特殊模块
- 系统类加载器(SystemClassLoader):负责加载用户类路径上所制定的类库
一般情况下,我们自己写的代码都是由系统类加载器去加载的
不同的类由什么类型的加载器去加载,载Java中已经被规定好了,不需要额外代码去实现
双亲委派模型
- 要求除了顶层的启动类加载器之外,其他的加载器都要有自己的父类加载器
- 这里的父子关系并不是extend的继承,而是逻辑上的继承
- 当我们使用最下面的类加载器加载一个字节码文件,首先不会自己尝试去加载,而是委派给自己的父类去完成
- 自定义的会交给系统类加载器去加载
- 类加载器会委托给平台类加载器去加载
- 平台类加载器会委托给启动类加载器去加载
- 当委托到启动类这个顶层的加载器时,不会继续向上委托,所以,所有的加载请求都会传递到启动类加载器中
- 传递委托也被认为是逻辑上的继承
- 每个加载器都有自己的加载范围,如果父类加载器无法加载请求时,便会一层一层往下返回
- 启动类–>平台类—>系统类—>自定义类
- 此时子加载器才会去尝试自己去加载字节码文件
代码演示:
/**
* @author zhangzengxiu
* @date 2022/12/5
*/
public class ClassLoaderDemo {
public static void main(String[] args) {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//平台类加载器
ClassLoader classLoader1 = systemClassLoader.getParent();
//启动类加载器
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println("系统类加载器=" + systemClassLoader);
System.out.println("平台类加载器=" + classLoader1);
System.out.println("启动类类加载器=" + classLoader2);
}
}
类加载器常用方法
方法名 | 说明 |
---|---|
public static ClassLoader getSystemClassLoader(); | 获取系统类加载器 |
public InputStream getResourceAsStream(String name); | 加载某一个资源文件 |
代码演示:
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* @author zhangzengxiu
* @date 2022/12/5
*/
public class ClassLoaderDemo2 {
public static void main(String[] args) throws IOException {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//利用加载器去获取一个指定的文件
InputStream is = systemClassLoader.getResourceAsStream("prop.properties");
Properties properties = new Properties();
properties.load(is);
}
}
反射
概述
Java反射机制
- 运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
- 对于任意对象,都能够调用它的任意属性和方法;
这种动态获取信息以及动态调用对象的功能称为Java语言的反射机制。
动态获取信息以及动态调用,取决于传过来什么类。
利用反射去调用它类中的属性和方法时,无视修饰符
先获取配置文件的信息,动态获取信息并创建对象和调用方法
获取class对象
- 利用class对象创建
- 反射创建对象
- 反射调用方法
说明:
class对象是由类加载器加载编译后的class字节码文件,并在内存中生成一个class对象。
该class对象中记录所有的信息,包括成员变量信息、静态变量信息等。
源码阶段:Class.forName(“全类名”)
class对象阶段:类名.class
Runtime运行时阶段:对象.getClass()
代码演示:
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.Stu");
System.out.println(clazz);
Class clazz2 = Stu.class;
System.out.println(clazz2);
Stu stu = new Stu();
Class clazz3 = stu.getClass();
System.out.println(clazz3);
}
}
获取Constructor对象
标准java类
package com.test.springcloud.domain;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Stu {
private String name;
private int age;
private Stu(String name){
System.out.println(name);
}
public Stu() {
System.out.println("public stu Constructor");
}
public Stu(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Stu{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
获取构造方法:
getConstructors能获取到所有公共的构造方法
代码演示:
import java.lang.reflect.Constructor;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
/*
获取所有公共构造方法对象的数组
Constructor<?>[] getConstructors()
*/
Class clazz = Class.forName("com.test.springcloud.domain.Stu");
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
}
getDeclaredConstructors能获取所有构造方法对象的数组
代码演示:
import java.lang.reflect.Constructor;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
/*
获取所有构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()
*/
Class clazz = Class.forName("com.test.springcloud.domain.Stu");
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
}
getConstructor根据传入的类型返回指定的构造器(只能获取到public修饰的)
代码演示:
import com.test.springcloud.domain.Stu;
import java.lang.reflect.Constructor;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
/*
获取单个构造方法对象
Constructor<?>[] getConstructor()
*/
Class clazz = Class.forName("com.test.springcloud.domain.Stu");
Constructor constructor = clazz.getConstructor(String.class, int.class);
System.out.println(constructor);
Constructor constructor1 = clazz.getConstructor();
System.out.println(constructor1);
}
}
如果根据传入的参数找不到对应的处理器则会报错:没有这样的构造
getDeclaredConstructor可以获取到任意修饰符修饰的构造方法
代码演示:
import java.lang.reflect.Constructor;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
/*
获取单个构造方法对象
Constructor<?>[] getDeclaredConstructor()
*/
Class clazz = Class.forName("com.test.springcloud.domain.Stu");
Constructor constructor = clazz.getDeclaredConstructor(String.class);
System.out.println(constructor);
}
}
总结:
- Constructor<?>[] getConstructors() :返回所有公共构造方法对象的数组
- Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
- Constructor getConstructor(Class<?>… parameterTypes):返回单个公共构造方法对象
- Constructor getDeclaredConstructor(Class<?>… parameterTypes):返回单个(任意)构造方法对象
利用Constructor创建对象
利用newInstance创建对象:
代码演示:
import java.lang.reflect.Constructor;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.Stu");
Constructor constructor = clazz.getConstructor(String.class, int.class);
//利用newInstance创建对象
Stu stu = (Stu) constructor.newInstance("zhangsan", 23);
System.out.println(stu);
}
}
class类中有个newInstance方法,简写格式
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.Stu");
Stu stu = (Stu)clazz.newInstance();
System.out.println(stu);
}
}
获取私有构造,并创建对象
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.Stu");
Constructor constructor = clazz.getDeclaredConstructor(String.class);
Stu stu = (Stu) constructor.newInstance("zhangsan");
System.out.println(stu);
}
}
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.Stu");
Constructor constructor = clazz.getDeclaredConstructor(String.class);
//被private修饰的成员,不能直接被使用,需要临时取消访问检查
constructor.setAccessible(true);
Stu stu = (Stu) constructor.newInstance("zhangsan");
System.out.println(stu);
}
}
总结:
- 获取class对象
三种方式—Class.forName(“全类名”)
- 获取构造方法对象
Constructor getConstructor(Class<?>... parameterTypes) Constructor getDeclaredConstructor(Class<?>… parameterTypes)
- 如果是public修饰的,直接创建对象
T newInstance(Object … initargs)
- 如果是非public,需要临时取消访问检查,然后再创建对象
constructor.setAccessible(true) 暴力反射
获取Field成员变量对象
- Field[] getFields():返回所有public公共的成员变量对象数组
- Field[] getDeclaredFields() :返回所有成员变量对象的数组,包括所有权限
- Field getField(String name):返回单个公共成员变量对象
- Field getDeclaredField(String name):返回单个成员变量对象,包括所有权限
public class User {
public String name;
public int age;
public String gender;
private int money = 100;
}
Field[] getFields():返回所有public公共的成员变量对象数组
代码演示:
import java.lang.reflect.Field;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//获取所有public公共的成员变量对象数组
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
Field[] getDeclaredFields() :返回所有成员变量对象的数组,包括所有权限
代码演示:
import java.lang.reflect.Field;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//获取所有成员变量对象的数组,包括所有权限
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
Field getField(String name):返回单个公共成员变量对象
代码演示:
import java.lang.reflect.Field;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//获取单个公共成员变量对象
Field field = clazz.getField("name");
System.out.println(field);
}
}
如果获取的成员变量不存在,则会报错:
注意点:
Field getField(String name)这个方法,想要获取到的变量必须是真实存在的,且必须是public修饰的
Field getDeclaredField(String name):返回单个成员变量对象,包括所有权限
代码演示:
import java.lang.reflect.Field;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//获取单个成员变量对象,无需考虑修饰符
Field field = clazz.getDeclaredField("money");
System.out.println(field);
}
}
- set(Object obj, Object value):给指定对象的成员变量赋值
- get(Object obj):返回指定对象的Field的值
set(Object obj, Object value):给指定对象的成员变量赋值
代码演示:
import com.test.springcloud.domain.User;
import java.lang.reflect.Field;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//获取单个成员变量对象,无需考虑修饰符
Field field = clazz.getField("name");
//反射空参创建对象
User user = (User) clazz.newInstance();
//赋值
field.set(user, "zhangsan");
System.out.println(user);
}
}
get(Object obj):返回指定对象的Field的值
代码演示:
import com.test.springcloud.domain.User;
import java.lang.reflect.Field;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//获取单个成员变量对象,无需考虑修饰符
Field field = clazz.getDeclaredField("money");
//私有的必须取消访问检查
field.setAccessible(true);
//反射空参创建对象
User user = (User) clazz.newInstance();
//获取值
Object obj = field.get(user);
System.out.println(obj);
}
}
获取Method方法对象
- Method[] getMethods():返回所有公共成员方法对象数组,包含继承的
- Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
- Method getMethod(String name, Class<?>… parameterTypes):返回单个公共成员方法对象
- Method getDeclaredMethod(String name, Class<?>… parameterTypes):返回单个成员方法对象
代码演示:
package com.test.springcloud.domain;
/**
* @author zhangzengxiu
* @date 2022/12/7
*/
public class User {
/**
* 私有无参无返回
*/
private void method1() {
System.out.println("私有 无参 无返回");
}
/**
* 公共有参无返回
*
* @param name
*/
public void method2(String name) {
System.out.println("公共 有参 无返回,参数=" + name);
}
/**
* 公共无参有返回
*
* @return
*/
public String method3() {
System.out.println("公共 无参 有返回");
return "qqq";
}
/**
* 公共有参有返回
*
* @param name
* @return
*/
public String method4(String name) {
System.out.println("公共 有参 有返回,参数=" + name);
return "qqq";
}
}
Method[] getMethods():返回所有公共成员方法对象数组,包含继承的
代码演示:
import java.lang.reflect.Method;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//返回所有公共成员方法对象数组,包含从父类继承的
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//返回所有成员方法对象的数组,不包括继承的
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
Method getMethod(String name, Class<?>… parameterTypes):返回单个公共成员方法对象
代码演示:
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//返回单个公共成员方法对象
Method method1 = clazz.getMethod("method0");
System.out.println(method1);
}
}
Method getDeclaredMethod(String name, Class<?>… parameterTypes):返回单个成员方法对象
代码演示:
import java.lang.reflect.Method;
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
//返回单个成员方法对象
Method method1 = clazz.getDeclaredMethod("method3", String.class);
System.out.println(method1);
}
}
- Object invoke(Object obj, Object… args):运行方法
参数解释:
obj:用obj对象调用该方法
args:调用方法的传递的参数(没有就不写)
返回值:方法的返回值(没有就不写)
代码演示:
/**
* @author zhangzengxiu
* @date 2022/12/6
*/
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.test.springcloud.domain.User");
Method method1 = clazz.getDeclaredMethod("method5", String.class);
User user = (User) clazz.newInstance();
//user是调用的对象
//第二个是传入的参数
Object res = method1.invoke(user, "zhangsan");
System.out.println(res);
}
}