目录
什么是类加载器?
类加载器的层次结构
类加载器的工作原理
双亲委派模型:
如何获取类加载器
获取类加载器的方法
url----输出绝对地址
InputStream--获取资源文件的输入流
使用 URL 和 InputStream
示例代码
如何从URL获取 InputStream 并读取数据:
注意事项
什么是类加载器?
类加载器(Class Loader)是 Java 虚拟机(JVM)的一部分,负责将类文件(.class 文件)加载到 JVM 中。类加载器在 Java 应用程序的启动和运行过程中起着至关重要的作用。
类加载器的层次结构
Java 类加载器采用层次结构,主要包括以下几种:
(1)Bootstrap Class Loader(引导类加载器)
负责加载 Java 核心库(如 rt.jar),位于 JAVA_HOME/jre/lib 目录下。
由原生代码实现,不是 Java 类,因此无法直接访问。
(2)Extension Class Loader(扩展类加载器)
负责加载 Java 的扩展库,位于 JAVA_HOME/jre/lib/ext 目录下。
实现为 sun.misc.Launcher$ExtClassLoader。
(3)Application Class Loader(应用类加载器)
也称为系统类加载器,负责加载应用程序类路径(CLASSPATH)下的类。
实现为 sun.misc.Launcher$AppClassLoader。
(4)Custom Class Loader(自定义类加载器)
开发者可以创建自定义类加载器,用于加载特定目录或网络路径下的类文件。
继承自 java.lang.ClassLoader 类。
类加载器的工作原理
双亲委派模型:
(1)当一个类加载器收到类加载请求时,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成。
(2)每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器。
(3)只有当父类加载器无法加载该类时,子类加载器才会尝试自己去加载。
如何获取类加载器
获取类加载器的方法
在Java中,有多种方式可以获取类加载器。以下是一些常见的方法:
获取当前类的类加载器 :ClassLoader classLoader = MyClass.class.getClassLoader();
获取当前线程上下文类加载器:
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
获取系统类加载器(应用程序类加载器):
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
获取启动类加载器
启动类加载器是用C++实现的,不能直接获取其引用。但是可以通过以下方式间接判断一个类是否由启动类加载器加载:ClassLoader bootstrapClassLoader = String.class.getClassLoader();if (bootstrapClassLoader == null) {System.out.println("This class is loaded by the Bootstrap Class Loader.");}
示例代码
以下是一些示例代码,展示了如何获取不同类型的类加载器:public class ClassLoaderExample {public static void main(String[] args) {// 获取当前类的类加载器ClassLoader currentClassLoader = ClassLoaderExample.class.getClassLoader();System.out.println("Current Class Loader: " + currentClassLoader);// 获取当前线程上下文类加载器ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();System.out.println("Context Class Loader: " + contextClassLoader);// 获取系统类加载器(应用程序类加载器)ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println("System Class Loader: " + systemClassLoader);// 获取启动类加载器ClassLoader bootstrapClassLoader = String.class.getClassLoader();if (bootstrapClassLoader == null) {System.out.println("String class is loaded by the Bootstrap Class Loader.");} else {System.out.println("String class loader: " + bootstrapClassLoader);}} }
输出示例
假设上述代码在一个标准的Java应用程序中运行,输出可能如下:Current Class Loader: sun.misc.Launcher$AppClassLoader@18b4aac2 Context Class Loader: sun.misc.Launcher$AppClassLoader@18b4aac2 System Class Loader: sun.misc.Launcher$AppClassLoader@18b4aac2 String class is loaded by the Bootstrap Class Loader.
解释
当前类的类加载器:ClassLoaderExample.class.getClassLoader() 返回加载 ClassLoaderExample 类的类加载器,通常是应用程序类加载器。
当前线程上下文类加载器:Thread.currentThread().getContextClassLoader() 返回当前线程的上下文类加载器,通常也是应用程序类加载器。
系统类加载器:ClassLoader.getSystemClassLoader() 返回系统类加载器,即应用程序类加载器。
启动类加载器:String.class.getClassLoader() 返回 null,表示 String 类是由启动类加载器加载的。
url----输出绝对地址
直接获取字节码的根路径
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); //URL 统一资源定位符, 其实里面维护了一个绝对路径 URL url = systemClassLoader.getResource("a.txt"); String path = url.getPath(); System.out.println(path);
InputStream--获取资源文件的输入流
可以直接读取字节码下面的资源!
//获取系统类加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); //找到根目录下的a.txt文档(当文件被加载后,只会保留src下面的文件),获取资源文件的输入流 InputStream in = systemClassLoader.getResourceAsStream("a.txt"); Properties properties = new Properties(); //将输入流对象传入 properties.load(in);
使用 URL 和 InputStream
在Java中,可以通过 URL 对象和 InputStream 来读取网络资源的内容。以下是一些常见的步骤和示例代码,展示如何从URL获取 InputStream 并读取数据。
步骤:
- 创建 URL 对象:使用 URL 类的构造函数或 URL 类的 new URL(String spec) 方法创建 URL 对象。
- 打开连接:调用 URL 对象的 openConnection() 方法获取 URLConnection 对象。
- 获取 InputStream:调用 URLConnection 对象的 getInputStream() 方法获取 InputStream。
- 读取数据:使用 InputStream 读取数据,通常会使用 BufferedReader 或其他流处理工具来简化操作。
- 关闭资源:读取完成后,关闭 InputStream 以释放资源。
示例代码
如何从URL获取 InputStream 并读取数据:
以下是一个完整的示例代码,展示了如何从URL获取 InputStream 并读取数据:import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection;public class URLInputStreamExample {public static void main(String[] args) {String urlString = "https://example.com";try {// 创建 URL 对象URL url = new URL(urlString);// 打开连接URLConnection connection = url.openConnection();// 获取 InputStreamtry (InputStream inputStream = connection.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {// 读取数据String line;while ((line = reader.readLine()) != null) {System.out.println(line);}}} catch (IOException e) {e.printStackTrace();}} }
注意事项
异常处理:在实际应用中,建议对 IOException 进行更详细的处理,例如记录日志或重试机制。
超时设置:可以通过 URLConnection 对象的 setConnectTimeout(int timeout) 和 setReadTimeout(int timeout) 方法设置连接和读取的超时时间,防止长时间阻塞。
字符编码:如果URL资源的编码不是默认的UTF-8,可以在 InputStreamReader 构造函数中指定编码,例如 new InputStreamReader(inputStream, "ISO-8859-1")。