类加载器(ClassLoader)
类加载、编译
类加载器用于将Java类(此时的Java类指的是已经从.java
编译成.class
的字节码文件)通过JVM加载到内存中才能运行。
编译java文件
包名为:
package com.melody.sec.classloader;
、类名称为:DefineClassDemo
-
编译java文件
javac com/melody/sec/classloader/DefineClassDemo.java
-
运行class文件
java com.melody.sec.classloader.DefineClassDemo
-
反编译class文件
javap -c -l -p com.melody.sec.classloader.DefineClassDemo
-
查看字节码具体内容
hexdump -C com/melody/sec/classloader/DefineClassDemo.class
请注意:
在java程序运行时涉及到类的概念,因此在运行class文件的时候使用的是类修饰限定的形式,而当在编译代码,查看文件内容的具体情况时,使用的是相对路径。「总结:当作文件利用时写文件名,当作类使用时写类名」
类加载器
类加载器有四类(Bootstrap ClassLoader(引导类加载器)
、Extension ClassLoader(扩展类加载器)
、App ClassLoader(系统类加载器)
),在其他文章中有明确解释,以及父类委派机制的流程,这里不在赘述。
父类委派机制:设计的初衷是为了防止攻击者恶意修改一些标准库中的类文件,因此通过父类委派机制对常规使用的类进行加载,防止其他人的恶意破坏。
「总结:对于某个类名(the binary name of a class
),总是先使用父类加载器对其进行加载,若无法加载在使用子类的类加载器」。
类加载器加载类的逻辑:
类名 -> 文件名->获取对应的class文件->读取class文件中字节码->将字节码加载到JVM中
理解了类加载器加载类的逻辑后,不妨提出几个问题:
- 如何获取类加载器,获取的类加载器是属于哪一种?
- 类加载器如何加载指定的类?
- 所有的类都有对应的类加载器吗?
下面,对上述问题进行逐一的解决。
获取类加载器
每一个类对象都包含了定义它的类加载器的引用。因此,获取类加载器的思路应该是从类对象中来。
-
获取当前类的类加载器
this.getClass().getClassLoader(); // sun.misc.Launcher$AppClassLoader@18b4aac2
-
获取其他包中的类的类加载器
ZipPath.class.getClassLoader(); // sun.misc.Launcher$ExtClassLoader@28d93b30
-
获取JVM在初始化时就加载的类的类加载器,即
Bootstrap ClassLoader
加载的类File.class.getClassLoader(); // null
所有类都有类加载器吗?
知道如何获取类加载器后,可以解决问题三,所有的类都有对应的类加载器吗?
查看官方文档,存在两种「特例」:
-
类数组加载时并不会使用类加载器进行加载,而是依赖于Java Runtime,但对数组类获取类加载器时,和对数据中的每个元素的类加载器是一致的。
public void solveProblem03(){ // 所有的类都有对应的类加载器吗? // Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; DefineClassDemo[] classDemos = new DefineClassDemo[3]; ClassLoader classLoader = classDemos.getClass().getClassLoader(); System.out.println(classLoader); // sun.misc.Launcher$AppClassLoader@18b4aac2 }
-
若类的类似是元类型,则没有类加载器
// if the element type is a primitive type, then the array class has no class loader. char[] bytes = "hello".toCharArray(); System.out.println(bytes.getClass().getClassLoader()); // null
类加载器如何加载类
类从哪里加载?
- 从文件系统加载类。(如CLASSPATH环境变量定义的类路径加载)
- 从远端服务器上加载类。