package com.atguigu.test03;
import org.junit.Test;
/*
* 一、类加载的过程由类加载器来完成。
* 类加载器:
* 1、引导类加载器(Bootstrap Classloader):又称为根类加载器
* 加载Java的核心库(JAVA_HOME/jre/lib/rt.jar等或sun.boot.class.path路径下的内容)
* 是用原生代码(C/C++)来实现的,并不继承自java.lang.ClassLoder,所以通过Java代码获取引导类加载器对象将会得到null
*
* 2、扩展类加载器(Extension ClassLoader)
* sun.misc.Launcher$ExtClassLoader
* 负责加载Java的扩展库(JAVA_HOME/jre/ext/*.jar或java.ext.dirs路径下的内容)
*
* 3、应用程序类加载器(Application Classloader)
* sun.misc.Launcher$AppClassLoader
* 负责加载Java应用程序类路径(classpath、java.class.path)下的内容
* 通俗的讲:项目的路径bin文件夹下的字节码,以及如果你配置了环境变量classpath
*
* 4、自定义类加载器
* 一般什么情况下需要自定义类加载器:
* (1)字节码需要加密和解密
* (2)字节码的路径不在常规路径,有自定特定的路径
* 例如:tomcat
*
* 二、如何获取某个类的类加载器对象?
* 1、获取某个类的Class对象
* 2、通过Class对象调用getClassLoader()方法获取类加载器对象
*
* 三、Java中类加载器的双亲委托模式
* 1、类加载器设计时,这四种类加载器是有层次结构的,但是这层次结构不是通过继承关系来实现。
* 但是是通过组合的方式,来实现“双亲”的认亲过程。
* 例如:应用程序类加载器把扩展类加载器称为“父加载器”,在应用程序类加载器中保留应用程序类加载器的一个引用,成员变量,把变量名称设计为parent。
* 所有的类加载器有一个getParent(),获取父加载器的方法。
*
* 2、有什么用?
* 目的:为了安全,而且各司其职
*
* 当应用程序类加载器接到加载某个类的任务时,例如:java.lang.String。
* (1)会现在内存中,搜索这个类是否加载过了,如果是,就返回这个类的Class对象,不去加载。
* (2)如果没有找到,即没有加载过。会把这个任务先提交给“父加载器”
*
* 当扩展类加载器接到加载某个类的任务时,例如:java.lang.String。
* (1)会现在内存中,搜索这个类是否加载过了,如果是,就返回这个类的Class对象,不去加载。
* (2)如果没有找到,即没有加载过。会把这个任务先提交给“父加载器”
*
* 当引导类加载器接到加载某个类的任务时,例如:java.lang.String。
* (1)会现在内存中,搜索这个类是否加载过了,如果是,就返回这个类的Class对象,不去加载。
* (2)如果没有找到,即没有加载过。会在它的负责的范围内尝试加载。
* 如果可以找到,那么就返回这个类的Class对象。就结束了。
* 如果没有找到,那么会把这个任务往回传,让“子加载器”扩展类加载器去加载。
*
* “子加载器”扩展类加载器接到“父加载器”返回的任务后,去它负责的范围内加载。
* 如果可以找到,那么就返回这个类的Class对象。就结束了。
* 如果没有找到,那么会把这个任务往回传,让“子加载器”应用程序类加载器去加载。
*
* “子加载器”应用程序类加载器接到“父加载器”返回的任务后,去它负责的范围内加载。
* 如果可以找到,那么就返回这个类的Class对象。就结束了。
* 如果没有找到,那么就报错ClassNotFoundException或java.lang.NoClassDefError
*
* Java中是认为不同的类加载器,加载的类名相同的类,识别为不同的类。
*
*/
public class TestClassLoader {
@Test
public void test04(){
//(1)先获取这个类的Class对象
Class clazz = TestClassLoader.class;
//(2)获取它的类加载器对象
ClassLoader loader = clazz.getClassLoader();
System.out.println("当前类的加载器:" + loader);
ClassLoader parent = loader.getParent();
System.out.println("父加载器:" + parent);
ClassLoader grand = parent.getParent();
System.out.println("爷爷加载器:" + grand);
}
@Test
public void test03() throws ClassNotFoundException{
//(1)先获取这个类的Class对象
Class clazz = Class.forName("com.atguigu.ext.demo.AtGuiguExtDemo");
//(2)获取它的类加载器对象
System.out.println(clazz.getClassLoader());
}
@Test
public void test02(){
//(1)先获取这个类的Class对象
Class clazz = String.class;
//(2)获取它的类加载器对象
ClassLoader loader = clazz.getClassLoader();
System.out.println(loader);
}
@Test
public void test01(){
//(1)先获取这个类的Class对象
Class clazz = TestClassLoader.class;
//(2)获取它的类加载器对象
ClassLoader loader = clazz.getClassLoader();
System.out.println(loader);
}
}
package com.atguigu.test04;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.junit.Test;
/*
* 类加载器的作用:
* 1、本质工作:加载类
* 2、顺便可以用它来加载“类路径下”的资源文件
* 例如:src下(编译后对应bin)有一个资源文件,配置文件:jdbc.properties
*
* 如何获取某个类的类加载器对象?
* 1、获取某个类的Class对象
* 2、通过Class对象调用getClassLoader()方法获取类加载器对象
*
* ClassLoader类加载器的类型:
* getResourceAsStream("资源文件的路径名")
*
* SourceFolder:源代码文件夹,一般会单独用一个config这种SourceFolder来装配置文件、等价于src
* 不同与普通的Folder
*/
public class TestClassLoader2 {
@Test
public void test5() throws IOException{
Properties pro = new Properties();//集合,map,key=value
Class clazz = TestClassLoader2.class;
ClassLoader loader = clazz.getClassLoader();
InputStream in = loader.getResourceAsStream("spring.properties");
pro.load(in);
System.out.println(pro);
System.out.println(pro.getProperty("user"));
}
@Test
public void test4() throws IOException{
Properties pro = new Properties();//集合,map,key=value
//在项目的根路径下,不在src里面
pro.load(new FileInputStream("out.properties"));
System.out.println(pro);
System.out.println(pro.getProperty("out"));
}
@Test
public void test3() throws IOException{
Properties pro = new Properties();//集合,map,key=value
Class clazz = TestClassLoader2.class;
ClassLoader loader = clazz.getClassLoader();
InputStream in = loader.getResourceAsStream("com/atguigu/test04/demo.properties");
pro.load(in);
System.out.println(pro);
System.out.println(pro.getProperty("name"));
}
@Test
public void test2() throws IOException{
Properties pro = new Properties();//集合,map,key=value
Class clazz = TestClassLoader2.class;
ClassLoader loader = clazz.getClassLoader();
InputStream in = loader.getResourceAsStream("jdbc.properties");
pro.load(in);
System.out.println(pro);
System.out.println(pro.getProperty("user"));
}
@Test
public void test1() throws IOException{
//相对路径在项目day24_code根目录下,不是相对src下
FileReader fr = new FileReader("jdbc.properties");
BufferedReader br = new BufferedReader(fr);
String str = br.readLine();
System.out.println(str);
br.close();
fr.close();
}
}
package com.atguigu.test05;
import java.io.Serializable;
import java.lang.annotation.ElementType;
import org.junit.Test;
/*
* 1、java.lang.Class类型:
* 所有的Java类型(包括基本数据类型、引用数据类型、void)
* 被加载到内存后,或者是编译器自动编译生成的class字节码,最终都会用一个Class对象来表示。
* 即,所有的Java类型,在内存中都表示为一个Class对象。
*
* 2、如何获取Class对象?4种 重点
* (1)类型名.class
* 优点:最简洁
* 缺点:要求编译期这个类型就要存在
*
* (2)对象.getClass()
* 这个方法在java.lang.Object类型中声明的,返回对象的运行时类型
*
* 适用于:你的先有对象
*
* (3)Class.forName("类型全名称")
* 类型全名称:包.类名
* 优势:这个类型可以在编译期间未知,这个类名称可以在代码中出现,也可以配置在配置文件中,或者键盘输入等方式来指定。
*
* (4)使用类加载器对象.loadClass("类型全名称")
* 一般都是用在自定义类加载器对象去加载指定路径下的类
*
* 这四种方式:都可以选择,你就看当前的情况,哪种能用,就用哪种,如果都能用,就用最简便的。
*/
public class TestClass {
@Test
public void test05() throws ClassNotFoundException{
Class c = TestClass.class;
ClassLoader loader = c.getClassLoader();
Class c2 = loader.loadClass("com.atguigu.test05.Employee");
Class c3 = Employee.class;
System.out.println(c2 == c3);
}
@Test
public void test04() throws ClassNotFoundException{
Class c = Class.forName("com.atguigu.ext.demo.AtGuiguExtDemo");
System.out.println(c);
}
@Test
public void test03() throws ClassNotFoundException{
Class c2 = String.class;
Class c1 = "".getClass();
Class c3 = Class.forName("java.lang.String");
System.out.println(c1 == c2);
System.out.println(c1 == c3);
}
@Test
public void test02(){
Class c2 = String.class;
Class c1 = "".getClass();
System.out.println(c1 == c2);
}
@Test
public void test01(){
Class c1 = int.class;//基本数据类型
Class c2 = void.class;//特殊的空类型
Class c3 = String.class;//系统定义的类类型
Class c4 = TestClass.class;//自定义的类的类类型
Class c5 = Serializable.class;//接口类型
Class c6 = ElementType.class;//枚举类型
Class c7 = Override.class;//注解类型
Class c8 = int[].class;
// Class c9 = Student.class;//错误的,因为编译期间不存在
// Class c10 = com.atguigu.ext.demo.AtGuiguExtDemo.class;//错误的,不在当前的类路径下
}
}