1.类加载器
1.1类加载器【理解】
Bootstrp加载器是用C++语言写的,它是在Java虚拟机启动后初始化的 平台类加载器:负责加载JDK中一些特殊的模块; 系统类加载器(System class loader)它也被称为应用程序类加载器, 它负责加载用户类路径上所指定的类库,一般情况下这个就是程序中默认的类加载器
-
作用
负责将.class文件(存储的物理文件)加载在到内存中。
写程序更加简洁。但是性能相对低。
tips:
-
演示java编译过程。
-
查看IDEA帮我们编译的程序跑到哪里了。
1.2类加载的过程【理解】
-
类加载时机
类在什么时候会被加载到内存中呢?
-
1.创建类的实例(对象)
-
2.调用类的类方法
-
3.访问类或者接口的类变量,或者为该类变量赋值
-
4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
-
5.初始化某个类的子类 (子类可以使用父类的方法)
-
6.直接使用java.exe命令来运行某个主类 main
-
总结:用到就加载,不用就不加载!!!
-
-
-
类加载过程
-
加载
-
通过包名 + 类名,获取这个类,准备用流进行传输
-
在这个类加载到内存中
-
加载完毕创建一个class对象
-
-
链接
-
验证
确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全
(文件中的信息是否符合虚拟机规范有没有安全隐患)
-
准备
负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值
(初始化静态变量)
-
解析
将类的二进制数据流中的符号引用替换为直接引用
(本类中如果用到了其他类,此时就需要找到对应的类)
在类的加载过程中的解析阶段,Java虚拟机会把类的二进制数据中的符号引用 替换为 直接引用。 如Worker类中一个方法: public void gotoWork(){ car.run(); //这段代码在Worker类中的二进制表示为符号引用 } 在Worker类的二进制数据中,包含了一个对Car类的run()方法的符号引用,它由run()方法的全名 和 相关描述符组成。在解析阶段,Java虚拟机会把这个符号引用替换为一个指针,该指针指向Car类的run()方法在方法区的内存位置,这个指针就是直接引用。
符号引用 :符号引用以一组符号来描述所引用的目标
直接引用:直接指向引用类对应的地址。
过程解释如下:
在解析阶段会有一个步将常量池当中二进制数据当中的符号引用转化为直接引用的过程 在编译的时候每个java类都会被编译成一个class文件,但在编译的时候虚拟机并不知道所引用类的地址,多以就用符号引用来代替,而在这个解析阶段就是为了把这个符号引用转化成为真正的地址的阶段。
-
-
初始化
根据程序员通过程序制定的主观计划去初始化类变量和其他资源
(静态变量赋值以及初始化其他资源)
小结
-
当一个类被使用的时候,才会加载到内存
-
类加载的过程: 加载、验证、准备、解析、初始化
-
问题:
-
静态属性何时加载,怎么用,和new的对象有啥区别。
-
静态方法,怎么用,和new的对象有啥区别。
-
静态代码块,怎么用,和new的对象有啥区别。
-
字节码对象,new 的对象有什么区别?
1.3类加载的分类【理解】
-
分类
-
1.启动类加载器(Bootstrap ClassLoader):虚拟机的内置类加载器,通常表示为null ,并且没有父null 启动类加载器是使用C++语言实现的(HotSpot),负责加载JVM虚拟机运行时所需的基本系统级别的类,如java.lang.String, java.lang.Object等等。 启动类加载器(Bootstrap Classloader)会读取 {JRE_HOME}/lib 下的jar包(如 rt.jar)和配置,然后将这些系统类加载到方法区内。由于类加载器是使用平台相关的底层C/C++语言实现的, 所以该加载器不能被Java代码访问到。
-
2.平台类加载器(Platform Classloader):也叫拓展类加载器,负责加载JDK中一些特殊的模块。
它负责加载 {JAVA_HOME}\lib\ext 目录下的类库, 开发者可以直接获取此加载器。
拓展类加载器是整个JVM加载器的Java代码可以访问到的类加载器的最顶端,即是超级父加载器,拓展类加载器是没有父类加载器的
-
3.系统类加载器(System Classloader):负责加载用户类路径上所指定的类库。
也称应用程序加载器是指 Sun公司实现的,它负责加载系统类路径java -classpath或-D java.class.path 指定路径下的类库,也就是我们经常用到的classpath路径,开发者可以直接使用系统类加载器,一般情况下该类加载是程序中默认的类加载器,
通过ClassLoader.getSystemClassLoader()方法可以获取到该类加载器。
-
-
类加载器的继承关系
-
System的父加载器为Platform
-
Platform的父加载器为Bootstrap
-
-
代码演示
public class ClassLoaderDemo1 { 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); //因为BootStrapClassLoader是用c++写的, //使用原生代码来实现,并不继承于java.lang.ClassLoader,所以在返回该ClassLoader时就会返回null } }
1.4双亲委派模型【理解】
-
介绍
ApplicationClassLoader(系统类加载器)中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器(平台类加载器)的loadClass方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。注意这个类似递归的过程,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。 为什么要设计这种机制?
这种设计有个好处是,如果有人想替换系统级别的类:String.java。篡改它的实现,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了(为什么?因为当一个类需要加载的时候,最先去尝试加载的就是BootstrapClassLoader),所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入 确保核心类加载的顺序的优先性
-
作用:保证JDK核心代码的优先执行!!!
-
应用场景:tomcat\nginx
String 类演示
User类
源码翻看:ClassLoader类---》loadClass(String name, boolean resolve)方法。
确保我们核心类优先执行权!!!
应用场景:Spring 模块优先执行。tomcat服务器项目。jetty服务器项目管理。
1.5ClassLoader 中的两个方法【应用】
-
方法介绍
方法名 说明 public static ClassLoader getSystemClassLoader() 获取系统类加载器 public InputStream getResourceAsStream(String name) 加载某一个资源文件 -
示例代码
public class ClassLoaderDemo2 { public static void main(String[] args) throws IOException { //static ClassLoader getSystemClassLoader() 获取系统类加载器 //InputStream getResourceAsStream(String name) 加载某一个资源文件 //获取系统类加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); //利用加载器去加载一个指定的文件 //参数:文件的路径(放在src的根目录下,默认去那里加载) //返回值:字节流。 InputStream is = systemClassLoader.getResourceAsStream("prop.properties"); Properties prop = new Properties(); prop.load(is); System.out.println(prop); is.close(); } }
-
jdbc.properties
-
加载
-
转为properties对象
-
获取键值
-
类加载器小结
-
作用:负责将.class文件(存储的物理文件)加载在到内存中。
-
加载过程
-
加载:把class文件加载到内存当中,类形式Class
-
验证:检验class中代码有没有违反java JVM规则
-
准备:为static修饰的变量和方法分配空间
-
解析:将类的二进制数据流中的符号引用替换为直接引用
-
初始化:静态变量赋值以及初始化其他资源
-
-
加载器分类:
-
Bootstrap class loader:虚拟机的内置类加载器,通常表示为null ,并且没有父null
-
Platform class loader:平台类加载器,负责加载JDK中一些特殊的模块
-
System class loader:系统类加载器,负责加载用户类路径上所指定的类库
-
-
加载器调用机制:双亲委派机制
-
作用:确保核心类加载的顺序的优先性
-
加载机制:内置类优先加载》jdk模块代码》项目中代码
-
应用场景:tomcat服务器项目模块调用机制、微服务项目核心模块优先性启动等场景。
-
-
ClassLoader:
-
getSystemClassLoader() 获取系统类加载器
-
getResourceAsStream(String name) 加载某一个资源文件
-
-
案例:用工具类读取prop.properties配置文件。
2.反射
说到反射,我们最容易想到的就是光的反射,看这里,我有一台X光机左边有一个人,然后通过x光机,我们得到了这样的一个影像。这个影像包含人身体的各个组成部分,然后我们可以根据哪里不好,对其进行操作。同样,我再来一个人,她然后通过x光机,也能得到同样的一个影像,这个影像包含人身体的各个组成部分。我们根据影像对人进行操作就可以了。下面我们来对比的说一下Java中使用的类
2.1反射的概述【理解】
我们在idea中 通过ctrl+p 可以查看一个方法对应的形参 那这个功能是如何实现的? 其实就是通过反射来完成的。
反射就是从类里面拿东西 。
那现在有一个问题 为什么不用io流来读取呢?
答:io流是从上下文往下 依次读取 当我们读取到 构造方法和成员方法的时候 并不好区分;并且 成员变量和局部变量也不好区分;
如下图 我们利用反射 可以获取到类中的每一个信息。
-
反射机制概念:
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意属性和方法; 这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
-
应用场景
-
通过配置文件去加载类
-
Spring IOC容器加载类(控制狂)
-
通过一个字符串(类路径)就能加载这个类
-
热部署
-
-
Java反射机制的好处
极大地提高了应用程序的扩展性。
-
多态弊端
-
Animal a = new Cat();
-
a.eat();
-
new 关键字成为了最大的弊端。new是万恶之源。
-
对象:
-
创建对象----------获取字节码对象
-
使用构造器------反射获取构造器
-
使用变量---------反射获取属性-修改属性
-
操作方法---------反射如何调用方法
2.2获取Class类对象的三种方式【应用】
-
三种方式分类
-
类名.class属性
-
对象名.getClass()方法
-
Class.forName(全类名)方法
-
-
示例代码
public class Student { private String name; private int age; public Student() { } public Student(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; } public void study(){ System.out.println("学生在学习"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public class ReflectDemo1 { public static void main(String[] args) throws ClassNotFoundException { //1.Class类中的静态方法forName("全类名") //全类名:包名 + 类名 Class clazz = Class.forName("com.itgaohe.myreflect2.Student"); System.out.println(clazz); //2.通过class属性来获取 Class clazz2 = Student.class; System.out.println(clazz2); //3.利用对象的getClass方法来获取class对象 //getClass方法是定义在Object类中. Student s = new Student(); Class clazz3 = s.getClass(); System.out.println(clazz3); System.out.println(clazz == clazz2);//true System.out.println(clazz2 == clazz3);//true } }
通过字节码对象获取:
-
构造方法并使用
-
成员变量并使用
-
成员方法并使用
2.3反射获取构造方法并使用【应用】
2.3.1Class类获取构造方法对象的方法
-
方法介绍
方法名 说明 Constructor<?>[] getConstructors() 返回所有公共构造方法对象的数组 Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组 Constructor<T> getConstructor(Class<?>... parameterTypes) 返回单个公共构造方法对象 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造方法对象 -
示例代码
public class Student { private String name; private int age; //私有的有参构造方法 private Student(String name) { System.out.println("name的值为:" + name); System.out.println("private...Student...有参构造方法"); } //公共的无参构造方法 public Student() { System.out.println("public...Student...无参构造方法"); } //公共的有参构造方法 public Student(String name, int age) { System.out.println("name的值为:" + name + "age的值为:" + age); System.out.println("public...Student...有参构造方法"); } }
public class ReflectDemo1 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { //method1(); //method2(); //method3(); //method4(); } private static void method1() throws ClassNotFoundException { // Constructor<?>[] getConstructors(): // 返回所有公共构造方法对象的数组 // 1.获取Class对象 Class clazz = Class.forName("com.itgaohe.myreflect3.Student"); Constructor[] constructors = clazz.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } } private static void method2() throws ClassNotFoundException { // Constructor<?>[] getDeclaredConstructors(): // 返回所有构造方法对象的数组 // 1.获取Class对象 Class clazz = Class.forName("com.itgaohe.myreflect3.Student"); Constructor[] constructors = clazz.getDeclaredConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } } private static void method3() throws ClassNotFoundException, NoSuchMethodException { // Constructor<T> getConstructor(Class<?>... parameterTypes): // 返回单个公共构造方法对象 // 1.获取Class对象 Class clazz = Class.forName("com.itgaohe.myreflect3.Student"); //小括号中,一定要跟构造方法的形参保持一致. Constructor constructor1 = clazz.getConstructor(); System.out.println(constructor1); Constructor constructor2 = clazz.getConstructor(String.class, int.class); System.out.println(constructor2); //因为Student类中,没有只有一个int的构造,所以这里会报错. Constructor constructor3 = clazz.getConstructor(int.class); System.out.println(constructor3); } private static void method4() throws ClassNotFoundException, NoSuchMethodException { // Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): // 返回单个构造方法对象 //1.获取Class对象 Class clazz = Class.forName("com.itgaohe.myreflect3.Student"); Constructor constructor = clazz.getDeclaredConstructor(String.class); System.out.println(constructor); } }
重点掌握: Constructor<T> getConstructor(Class<?>... parameterTypes) 返回单个公共构造方法对象
2.3.2Constructor类用于创建对象的方法
-
方法介绍
方法名 说明 T newInstance(Object...initargs) 根据指定的构造方法创建对象 setAccessible(boolean flag) 设置为true,表示取消访问检查 被private修饰的成员,不能直接使用的 如果用反射强行获取并使用,需要临时取消访问检查 放在获取构造器之前。
-
示例代码
// Student类同上一个示例,这里就不在重复提供了 public class ReflectDemo2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //T newInstance(Object... initargs):根据指定的构造方法创建对象 //method1(); //method2(); //method3(); //method4(); } private static void method1() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { //1.获取class对象 Class clazz = Class.forName("com.itgaohe.myreflect3.Student"); //2.获取构造方法对象 Constructor constructor = clazz.getConstructor(String.class, int.class); //3.利用newInstance创建Student的对象 Student student = (Student) constructor.newInstance("zhangsan", 23); System.out.println(student); } private static void method2() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { //1.获取class对象 Class clazz = Class.forName("com.itgaohe.myreflect3.Student"); //2.获取构造方法对象 Constructor constructor = clazz.getConstructor(); //3.利用空参来创建Student的对象 Student student = (Student) constructor.newInstance(); System.out.println(student); } private static void method3() throws ClassNotFoundException, InstantiationException, IllegalAccessException { //简写格式 //1.获取class对象 Class clazz = Class.forName("com.itgaohe.myreflect3.Student"); //2.在Class类中,有一个newInstance方法,可以利用空参直接创建一个对象 Student student = (Student) clazz.newInstance(); //这个方法现在已经过时了,了解一下 System.out.println(student); } private static void method4() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { //获取一个私有的构造方法并创建对象 //1.获取class对象 Class clazz = Class.forName("com.itgaohe.myreflect3.Student"); //2.获取一个私有化的构造方法. Constructor constructor = clazz.getDeclaredConstructor(String.class); //被private修饰的成员,不能直接使用的 //如果用反射强行获取并使用,需要临时取消访问检查 constructor.setAccessible(true); //3.直接创建对象 Student student = (Student) constructor.newInstance("zhangsan"); System.out.println(student); } }
2.3.3小结
-
获取class对象
三种方式: Class.forName(“全类名”), 类名.class, 对象名.getClass()
-
获取里面的构造方法对象
getConstructor (Class<?>... parameterTypes) getDeclaredConstructor (Class<?>... parameterTypes)
-
如果是public的,直接创建对象
newInstance(Object... initargs)
-
如果是非public的,需要临时取消检查,然后再创建对象
setAccessible(boolean) 暴力反射
2.4反射获取成员变量并使用【应用】
2.4.1Class类获取成员变量对象的方法
-
方法分类
方法名 说明 Field[] getFields() 返回所有公共成员变量对象的数组 Field[] getDeclaredFields() 返回所有成员变量对象的数组 Field getField(String name) 返回单个公共成员变量对象 Field getDeclaredField(String name) 返回单个成员变量对象 -
示例代码
public class Student { public String name; public int age; public String gender; private int money = 300; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + ", money=" + money + '}'; } } public class ReflectDemo1 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { // method1(); //method2(); //method3(); //method4(); } private static void method1() throws ClassNotFoundException { // Field[] getFields():返回所有公共成员变量对象的数组 //1.获取class对象 Class clazz = Class.forName("com.itgaohe.myreflect4.Student"); //2.获取Field对象. Field[] fields = clazz.getFields(); //3.遍历 for (Field field : fields) { System.out.println(field); } } private static void method2() throws ClassNotFoundException { // Field[] getDeclaredFields():返回所有成员变量对象的数组 //1.获取class对象 Class clazz = Class.forName("com.itgaohe.myreflect4.Student"); //2.获取所有的Field对象 Field[] fields = clazz.getDeclaredFields(); //3.遍历 for (Field field : fields) { System.out.println(field); } } private static void method3() throws ClassNotFoundException, NoSuchFieldException { // Field getField(String name):返回单个公共成员变量对象 //想要获取的成员变量必须是真实存在的 //且必须是public修饰的. //1.获取class对象 Class clazz = Class.forName("com.itgaohe.myreflect4.Student"); //2.获取name这个成员变量 //Field field = clazz.getField("name"); //Field field = clazz.getField("name1"); Field field = clazz.getField("money"); //3.打印一下 System.out.println(field); } private static void method4() throws ClassNotFoundException, NoSuchFieldException { // Field getDeclaredField(String name):返回单个成员变量对象 //1.获取class对象 Class clazz = Class.forName("com.itgaohe.myreflect4.Student"); //2.获取money成员变量 Field field = clazz.getDeclaredField("money"); //3.打印一下 System.out.println(field); } }
2.4.2Field类用于给成员变量赋值的方法
-
方法介绍
方法名 说明 void set(Object obj, Object value) 给指定对象的成员变量赋值 Object get(Object obj) 获取指定对象的成员变量的值 -
示例代码
// Student类同上一个示例,这里就不在重复提供了 public class ReflectDemo2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException { // void set(Object obj, Object value)给指定对象的成员变量赋值 // Object get(Object obj)获取给指定对象的成员变量的值 // 1. 获取字节码对象 Class<?> aClass = Class.forName("itgaohe1.Student"); // 2. 通过字节码获取成员变量 Field field = aClass.getField("age"); System.out.println(field); // 3. 通过字节码对象获取到实体对象 Student student = (Student) aClass.newInstance(); // 4. 获取值 Object o = field.get(student); System.out.println(o); // 5.设置值 field.set(student,100); // System.out.println(field.get(student)); System.out.println(student.getAge()); }
2.5反射获取成员方法并使用【应用】
2.5.1Class类获取成员方法对象的方法
-
方法分类
方法名 说明 Method[] getMethods() 返回所有公共成员方法对象的数组,包括继承的 Method[] getDeclaredMethods() 返回所有成员方法对象的数组,不包括继承的 Method getMethod(String name, Class<?>... parameterTypes) 返回单个公共成员方法对象 Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象 -
示例代码
public class Student { //私有的,无参无返回值 private void show() { System.out.println("私有的show方法,无参无返回值"); } //公共的,无参无返回值 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 ReflectDemo1 { - }
2.5.2Method类用于执行方法的方法
-
方法介绍
方法名 说明 Object invoke(Object obj, Object... args) 运行方法 参数一: 用obj对象调用该方法
参数二: 调用方法的传递的参数(如果没有就不写)
返回值: 方法的返回值(如果没有就不写)
-
示例代码
public class ReflectDemo2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { // Object invoke(Object obj, Object... args):运行方法 // 参数一:用obj对象调用该方法 // 参数二:调用方法的传递的参数(如果没有就不写) // 返回值:方法的返回值(如果没有就不写) //1.获取class对象 Class clazz = Class.forName("com.itgaohe.myreflect5.Student"); //2.获取里面的Method对象 function4 Method method = clazz.getMethod("function4", String.class); //3.运行function4方法就可以了 //3.1创建一个Student对象,当做方法的调用者 Student student = (Student) clazz.newInstance(); //3.2运行方法 Object result = method.invoke(student, "zhangsan"); //4.打印一下返回值 System.out.println(result); } }
2.6 反射的案例
需求:用classpath.properties文件存储User类路径全名,读取配置文件,并用反射的思想完成user对象的创建、属性赋值、方法调用。
配置文件配置例如:classpath=com.itgaohe.User
步骤: //1. 读取配置文件 //2. 获取类路径全名称 //3. 反射获取类class对象 //4. 获取类构造器对象 //5. 获取类对象 //6. 参数 hoppy 赋值 取值 //7. eat方法调用
public class Demo { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { //1. 读取配置文件 Properties prop = new Properties(); InputStream in = Demo.class.getClassLoader().getResourceAsStream("classpath.properties"); prop.load(in); //2. 获取类路径全名称 String classpath = prop.getProperty("classpath"); //3. 反射获取类class对象 Class<?> aClass = Class.forName(classpath); //4. 获取类构造器对象 Constructor<?> constructor = aClass.getConstructor(); //5. 获取类对象 User user = (User) constructor.newInstance(); //6. 参数 hoppy 赋值 取值 Field field = aClass.getField("hoppy"); field.set(user,"小米"); Object hoppy = field.get(user); System.out.println(hoppy); //7. eat方法调用 Method eat = aClass.getMethod("eat", String.class); Object obj = eat.invoke(user, "大米饭"); System.out.println(obj); } }
public class User { public String hobby; public String eat(String hobby){ System.out.println("喜欢吃" + hobby); return hobby; } }
2.7 案例
在程序运行中,通过配置文件修改版本类。
-
path.properties
-
Verson接口
-
V1 类
-
-
V2 类
-
Demo测试 模拟程序的持续运行
今日总结
-
类加载器
-
作用:负责将.class文件(存储的物理文件)加载在到内存中。
-
加载过程
-
加载:把class文件加载到内存当中,类形式Class
-
验证:检验class中代码有没有违反java JVM规则
-
准备:为static修饰的变量和方法分配空间,赋初始值
-
解析:将类的二进制数据流中的符号引用替换为直接引用
-
初始化:静态变量赋值以及初始化其他资源
-
-
加载器分类:
-
Bootstrap class loader:虚拟机的内置类加载器,通常表示为null ,并且没有父null
-
Platform class loader:平台类加载器,负责加载JDK中一些特殊的模块
-
System class loader:系统类加载器,负责加载用户类路径上所指定的类库
-
-
加载器调用机制:双亲委派机制
-
作用:确保核心类加载的顺序的优先性
-
加载机制:内置类优先加载》jdk模块代码》项目中代码
-
应用场景:tomcat服务器项目模块调用机制、微服务项目核心模块优先性启动等场景。
-
-
ClassLoader:
-
getSystemClassLoader() 获取系统类加载器
-
getResourceAsStream(String name) 加载某一个资源文件
-
-
案例:用工具类读取prop.properties配置文件。
-
-
反射
-
概念:运行状态中,对于任意一个类,都能够知道、调取这个类的所有属性和方法。
-
使用场景:spring框架加载类、Servlet类调用、热部署等。
-
优点:只需要类的路径全名称就可以调用这个类的方法、属性和创建对象。不需要new,不需要关闭服务器。
-
反射获取Class类对象:
-
类名.class属性
-
对象名.getClass()方法
-
Class.forName(全类名)方法
-
-
反射获取构造方法
-
getConstructors() 返回所有公共构造方法对象的数组
-
getDeclaredConstructors() 返回所有构造方法对象的数组
-
getConstructor(Class<?>... parameterTypes) 返回单个公共构造方法对象
-
getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造方法对象
-
-
反射创建对象
-
newInstance(Object...initargs) 根据指定的构造方法创建对象
-
setAccessible(boolean flag) 设置为true,表示取消访问检查
-
-
反射获取变量并使用
-
getFields() 返回所有公共成员变量对象的数组
-
getDeclaredFields() 返回所有成员变量对象的数组
-
getField(String name) 返回单个公共成员变量对象
-
getDeclaredField(String name) 返回单个成员变量对象
-
set(Object obj, Object value) 给指定对象的成员变量赋值(obj载体对象)
-
get(Object obj) 获取指定对象的成员变量的值
-
-
反射获取成员方法并使用
-
Method[] getMethods() 返回所有公共成员方法对象的数组,包括继承的
-
getDeclaredMethods() 返回所有成员方法对象的数组,不包括继承的
-
getMethod(String name, Class<?>... parameterTypes) 返回单个公共成员方法对象
-
getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象
-
invoke(Object obj, Object... args) 运行方法(obj载体对象)
-
-
反射案例:
-
通过配置文件获取类,并使用。
-
-
能力目标
-
理解双亲委派机制
-
需求:用classpath.properties文件存储学生类路径全名,读取配置文件,并用反射的思想完成user对象的创建、属性赋值、方法调用。
-
热部署。