1、类加载
当程序要使用某个类时,如果该类还未被加载到内存中,系统则会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化,如果不出现意外情况,JVM将会连续完成这三个步骤,这三个步骤被称为类加载或类初始化。
类的加载:
把class文件读入内存,并创建java.lang.Class对象。任何类被使用时,系统都会为之建立一个java.lang.Class对象。
类的连接;
验证阶段:检验被加载的类是否有正确的内部结构,并和其他类协调一致。
准备阶段:负责为类变量分配内存,并设置默认值。
解析阶段:把类的二进制数据中的符号引号替换为直接引用。
类的初始化:主要是是对类变量进行初始化。
类的初始化步骤:
假如还未被加载和连接,则程序先加载并连接该类。
假如该类的直接父类还未被初始化,则先初始化其直接父类。
假如类中有初始化语句,则一次执行这些初始化语句。
类的初始化时机:
创建类的实例。
调用类的方法。
访问类或接口的类变量,或者为类变量赋值。
使用反射方式强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令运行某个类。
2、类加载器
2.1、类加载器的作用:
负责将.class文件加载到内存中,并生成java.lang.Class对象。
2.2、JVM类加载机制
全盘负责:就是当一个类加载器负责加载某一个类时,该类所依赖和所引用其他类也有该类加载器负责载入,除非显示使用另一个类加载器来载入。
父类委托:当一个类加载器负责加载某个class时,先让付类加载器试图加载该class,只有父类加载器无法加载时,才尝试从自己的类路径中加载该类。
缓存机制:先从缓存区中搜索该class,不存在则读取二进制数据,转换为class对象,存储到缓存中。
2.3、类加载器
ClassLoader:是负责加载类的对象
ClassLoader loader = ClassLoader.getSystemClassLoader()
Bootstrap类加载器:虚拟机的内置类加载器
Platform class loader 平台类加载器
System class loader 应用程序类加载器
3、反射
3.1、反射:是指在运行时去获取一个类的变量和方法信息,然后通过获取到的信息创建对象,调用方法的一种机制。
3.2、获取Class类的对象
第一种:使用类的class属性得到Class对象。
Class c1 = Student.class;
Class c1 = Student.class;
sout(c1 == c2) //返回true
第二种:调用对象的getClass()方法
Student stu = new Student();
Class<? extends Student> c3 = stu.getClass(); sout(c1 == c3) //返回true 第三种:使用class中的静态方法forName(String className) Class<?> c4 = Class.forName(“com.test.Student”);
3.3、反射获取构造方法并使用
Class<?> c4 = Class.forName(“com.test.Student”);
Construtor<?>[] cons = c4.getConstructors();//只能拿到公共的构造方法
Construtor<?>[] cons2 c4.DeclaredConstrutos();//拿所有的构造方法
Construtor cons = c4.getConstructor(参数类型的字节码类型…)
//返回单个公共构造方法
Construtor cons = c4.getDeclaredConstructor(参数类型的字节码类型…)
//返回单个构造方法,可以是私有的
3.4、反射创建对象的过程
Class<?> c4 = Class.forName("com.test.Student"); Construtor<?> con = c4.getConstructor();
Object obj = con.newInstance();
测试代码为:
Class<?> c = Class.forName("com.learn.day20220419.Student");
Constructor<?> con = c.getDeclaredConstructor(String.class, Integer.class);
//1.获取普通构造法方法,直接创建对象
Object stu = con.newInstance("zhangsan", 22);
System.out.println(stu);
//2.获取私有的构造方法,暴力创建对象
Constructor<?> con2 = c.getDeclaredConstructor(String.class);
con2.setAccessible(true);//私有方法需要设置,不然创建对象会报错
Object stu2 = con2.newInstance("lisi");
System.out.println(stu2);
4、获取字段
4.1、获取所有公共的字段,返回一个数组
Class<?> c = Class.forName(“com.learn.day20220419.Student”);
Field[] fields = c.getFields();
4.2、获取所有字段,返回一个数组
Field[] declaredFields = c.getDeclaredFields();
4.3、获取指定一个公共字段
4.4、获取一个指定字段
5、笔记
//1、获取所有公共构造方法
System.out.println("1、获取所有公共构造方法--------------------------------------");
Class<?> c = Class.forName("com.yan.test.Student");
Constructor<?>[] cons = c.getConstructors();
Stream.of(cons).forEach(con -> System.out.println(con));
//2、获取所有构造方法,包括私有构造
System.out.println("2、获取所有构造方法,包括私有构造-------------------------------");
cons = c.getDeclaredConstructors();
Stream.of(cons).forEach(con -> System.out.println(con));
//3、根据参数类型获取指定公共构造方法
System.out.println("3、根据参数类型获取公共构造方法--------------------------------");
Constructor<?> con = c.getConstructor(String.class, Integer.class, String.class);
System.out.println(con);
//4、根据参数类型获取指定构造方法,包括私有方法
System.out.println("4、根据参数类型获取指定构造方法,包括私有方法---------------------");
con = c.getDeclaredConstructor(String.class, Integer.class);
System.out.println(con);
//5、通过构造方法给对象赋值
System.out.println("5、通过构造方法给对象赋值--------------------------------------");
con = c.getDeclaredConstructor(String.class, Integer.class, String.class);
con.setAccessible(true);
Object obj = con.newInstance("zhangsan", 20, "wuhan");
System.out.println(obj);
//6、获取所有公共字段
System.out.println("6、获取所有公共字段----------------------------------------------");
Field[] fields = c.getFields();
Stream.of(fields).forEach(field -> System.out.println(field));
//7、获取所有字段,包括私有
System.out.println("7、获取所有字段,包括私有-----------------------------------------");
fields = c.getDeclaredFields();
Stream.of(fields).forEach(field -> System.out.println(field));
//8、获取指定公共字段
System.out.println("8、获取指定公共字段----------------------------------------------");
Field addressField = c.getField("address");
System.out.println(addressField);
//9、获取指定字段,包括私有
System.out.println("9、获取指定字段,包括私有------------------------------------------");
Field nameField = c.getDeclaredField("name");
System.out.println(nameField);
//10、给字段赋值
System.out.println("10、给字段赋值--------------------------------------------------");
//先创建一个对象
Class<?> c2 = Class.forName("com.yan.test.Student");
Constructor<?> con2 = c2.getDeclaredConstructor();
con2.setAccessible(true);
Object obj2 = con2.newInstance();
//获取字段
Field nameField2 = c2.getDeclaredField("name");
nameField2.setAccessible(true);
nameField2.set(obj2, "zhangsan");
//取出字段的值
System.out.println(nameField2.get(obj2));
//11、获取所有公共方法,包含集成和实现的方法
System.out.println("11、获取所有公共方法,包含集成和实现的方法---------------------------");
Method[] methods = c.getMethods();
Stream.of(methods).forEach(method -> System.out.println(method));
//12、获取所有方法,只是本类中的方法,不包含集成和实现的方法
System.out.println("12、获取所有方法,只是本类中的方法,不包含集成和实现的方法---------------");
methods = c.getDeclaredMethods();
Stream.of(methods).forEach(method -> System.out.println(method));
//13、获取指定公共方法
System.out.println("13、获取指定公共方法----------------------------------------------");
Method show1Method = c.getMethod("show1");
System.out.println(show1Method);
//14、获取指定方法,包括私有
System.out.println("14、获取指定方法,包括私有-----------------------------------------");
Method show2Method = c.getDeclaredMethod("show2", String.class);
System.out.println(show2Method);
//15、调用方法
System.out.println("15、调用方法----------------------------------------------------");
//创建对象
Class<?> c3 = Class.forName("com.yan.test.Student");
Constructor<?> con3 = c3.getDeclaredConstructor(String.class, Integer.class, String.class);
con3.setAccessible(true);
Object obj3 = con3.newInstance("zhangsan", 20, "wuhan");
//获取方法
Method show2Method3 = c3.getDeclaredMethod("show2", String.class);
show2Method3.setAccessible(true);
show2Method3.invoke(obj3, "nike");