Java 之 类加载器对象—ClassLoader

一、获取 ClassLoader 对象

  获取某个类的类加载对象需要两步:

  ① 获取某个类的 Class  对象;

  ② 通过 Class 对象调用 getClassLoader() 方法获取类加载器对象

二、java.lang.ClassLoader 对象

  ClassLoader 类是一个抽象类,学习一下 ClassLoader 的相关方法:

public final ClassLoader getParent():返回委托的父类加载器。一些实现可能使用 null 来表示引导类加载器;
public static ClassLoader getSystemClassLoader():返回委托的系统类加载器;
public Class<?> loadClass(String name):使用指定的二进制名称(类的全限定名)来加载类。
    例如:java.lang.String,注意内部类的名称:匿名内部类(外部类的全限定名$编号)、局部内部类(外部类的全限定名$编号+类名)、成员/静态内部类(外部类的全限定名$+类名); protected Class<?> findClass(String name):使用指定的二进制名称(类的全限定名)来查找类。此方法应该被类加载器的实现重写,该实现按照委托模型来加载类。
                          在通过父类加载器检查所请求的类后,此方法将被 loadClass 方法调用; protected final Class<?> findLoadedClass(String name):返回Class 对象,如果类没有被加载,则返回 null; protected final Class<?> defineClass(String name,byte[] b,int off,int len):将一个 byte 数组转换为 Class 类的实例;

  

   Demo:自定义类加载器示例

 1 import java.io.ByteArrayOutputStream;
 2 import java.io.File;
 3 import java.io.FileInputStream;
 4 import java.io.FileNotFoundException;
 5 import java.io.IOException;
 6 import java.io.InputStream;
 7 
 8 public class FileClassLoader extends ClassLoader{
 9     private String rootDir;//指定加载路径
10     
11     public FileClassLoader(String rootDir){
12         this.rootDir = rootDir;
13     }
14     
15     @Override
16     protected Class<?> findClass(String name) throws ClassNotFoundException {
17         //首先检查请求的类型是否已经被这个类装载器装载到命名空间中了,如果已经被装载,直接返回;
18         Class<?> c = findLoadedClass(name);
19         
20         if(c ==null){
21             //委派类加载器请求给父类加载器,如果父类加载器能够完成,则返回父类加载器加载的Class实例;
22             ClassLoader parent = this.getParent();
23             try {
24                 c = parent.loadClass(name);
25                 //加异常处理,父类加载不到,然后自己加载
26             } catch (Exception e) {
27             }
28             
29             //调用本类加载器的findClass()方法,试图获取对应的字节码,如果获取的到,则调用defineClass()导入类型到方法区;
30             //如果获取不到对应的字节码或其他原因失败,则异常,终止加载过程
31             if(c == null){
32                 byte[] classData = getClassData(name);
33                 if(classData == null){
34                     throw new ClassNotFoundException();
35                 }else{
36                     c = defineClass(name, classData, 0, classData.length);
37                 }
38             }
39         }
40         return c;
41     }
42     
43     //把.class文件的内容读取到一个字节数组中
44     //为什么要读取的字节数组中,因为protected final Class<?> defineClass(String name,byte[] b,int off,int len)
45     private byte[] getClassData(String name) {
46         String path = rootDir + File.separator + name.replace(".", File.separator)+".class";
47         InputStream is = null;
48         ByteArrayOutputStream baos = null;
49         try {
50             is = new FileInputStream(path);
51             baos =new ByteArrayOutputStream(); 
52             byte[] buffer = new byte[1024];
53             int len;
54             while((len = is.read(buffer))!=-1){
55                 baos.write(buffer, 0, len);
56             }
57             return baos.toByteArray();
58         } catch (FileNotFoundException e) {
59             e.printStackTrace();
60         } catch (IOException e) {
61             e.printStackTrace();
62         }finally{
63             try {
64                 if(is!=null){
65                     is.close();
66                 }
67             } catch (IOException e) {
68                 e.printStackTrace();
69             }
70         }
71         return null;
72     }
73 }
74 
75 public class TestFileClassLoader {
76 
77     public static void main(String[] args) throws ClassNotFoundException {
78         FileClassLoader fsc = new FileClassLoader("D:/java/code");
79         Class<?> uc = fsc.loadClass("com.ks.UserManager");
80         System.out.println(uc);
81         
82         Class<?> sc = fsc.loadClass("java.lang.String");
83         System.out.println(sc);
84         System.out.println(sc.getClassLoader());//null,因为委托给父类加载器...一直到引导类加载器
85     }
86 
87 }

三、类加载器加载资源文件

  ClassLoader 类的职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java类,即 java.lang.Class 类的一个实例。除此之外,ClassLoader 还负责加载 Java 应用所需的资源,如图像文件和配置文件等。

  案例一:加载类路径(如:src 下)jdbc.properties 资源文件

      扩展:SourceFolder:源代码文件夹,一般会单独用一个config这种SourceFolder来装配置文件、等价于src,不同于普通的 Folder

        代码示例:

 1 username=root
 2 password=123456
 3 url=jdbc:mysql://localhost:3306/test
 4 
 5 package com.atguigu.loader;
 6 
 7 import java.io.IOException;
 8 import java.util.Properties;
 9 
10 public class TestLoaderProperties {
11     public static void main(String[] args) {
12         Properties pro = new Properties();
13         try {
14             pro.load(ClassLoader.getSystemResourceAsStream("jdbc.properties"));
15             System.out.println(pro);
16         } catch (IOException e) {
17             e.printStackTrace();
18         }
19                 System.out.println(pro);
20         System.out.println(pro.getProperty("username"));
21     }
22 }
23         

  案例二:获取存放在“com.ks.reflect” 包下面的 demo.properties 文件

      代码示例:

 1   @Test
 2     public void test() throws IOException{
 3         Properties pro = new Properties();//集合,map,key=value
 4         
 5         Class clazz = Test.class;   //获取本类的 Class 对象
 6         ClassLoader loader = clazz.getClassLoader();  //获取类加载器
 7         InputStream in = loader.getResourceAsStream("com/ks/reflect/demo.properties");
 8         
 9         pro.load(in);
10         
11         System.out.println(pro);
12         System.out.println(pro.getProperty("name"));
13     }

  案例三:获取当前项目下的 out.properties 文件,不在 src 下面(这个文件没有在编译目录下,不需要使用类加载器)

      代码示例:

 1    @Test
 2     public void test() throws IOException{
 3         Properties pro = new Properties(); 4         
 5         //在项目的根路径下,不在src里面
 6         pro.load(new FileInputStream("out.properties"));
 7         
 8         System.out.println(pro);
 9         System.out.println(pro.getProperty("out"));
10     }
原文地址:https://www.cnblogs.com/niujifei/p/12311385.html