Java SE
Java平台共分为三个主要版本Java SE(Java Platform, Standard Edition-Java平台标准版)、Java EE(Java Platform Enterprise Edition-Java平台企业版)、和Java ME(Java Platform, Micro Edition-Java平台微型版)。Java SE是JDK自带的标准API,内容涉及范围甚广,知识体系更是环环相扣浩瀚无边。本章节整理了一些Java SE基础部分与Java SE安全相关的基础知识供初学者学习进阶。
ClassLoader(类加载机制)
Java是一个依赖于JVM(Java虚拟机)实现的跨平台开发语言。Java程序在运行前需要先编译成class文件,Java类初始化的时候会调用java.lang.ClassLoader加载类字节码,ClassLoader会调用JVM的native方法来定义一个java.lang.Class实例。
JVM架构图:

Java类
Java是编译型语言,我们编写的java文件需要编译成后class文件后才能够被JVM运行,学习ClassLoader之前我们先简单了解下Java类。
示例TestHelloWorld.java:
package xin.xyyanquan.sec.classloader;
public class TestHelloWorld {
public String hello() {
return "Hello World~";
}
}编译TestHelloWorld.java:javac TestHelloWorld.java
我们可以通过JDK自带的javap命令反汇编TestHelloWorld.class文件对应的xin.xyyanquan.sec.classloader.TestHelloWorld类,以及使用Linux自带的hexdump命令查看TestHelloWorld.class文件二进制内容
ClassLoader
一切的Java类都必须经过JVM加载后才能运行,而ClassLoader的主要作用就是Java类文件的加载。在JVM类加载器中最顶层的是Bootstrap ClassLoader(引导类加载器)、Extension ClassLoader(扩展类加载器)、App ClassLoader(系统类加载器),AppClassLoader是默认的类加载器,如果类加载时我们不指定类加载器的情况下,默认会使用AppClassLoader加载类,ClassLoader.getSystemClassLoader()返回的系统类加载器也是AppClassLoader。
值得注意的是某些时候我们获取一个类的类加载器时候可能会返回一个null值,如:java.io.File.class.getClassLoader()将返回一个null对象,因为java.io.File类在JVM初始化的时候会被Bootstrap ClassLoader(引导类加载器)加载(该类加载器实现于JVM层,采用C++编写),我们在尝试获取被Bootstrap ClassLoader类加载器所加载的类的ClassLoader时候都会返回null。
ClassLoader类有如下核心方法:
loadClass(加载指定的Java类)findClass(查找指定的Java类)findLoadedClass(查找JVM已经加载过的类)defineClass(定义一个Java类)resolveClass(链接指定的Java类)
Java类动态加载方式
Java类加载方式分为显式和隐式,显式即我们通常使用Java反射或者ClassLoader来动态加载一个类对象,而隐式指的是类名.方法名()或new类实例。显式类加载方式也可以理解为类动态加载,我们可以自定义类加载器去加载任意的类。
常用的类动态加载方式:
// 反射加载TestHelloWorld示例
Class.forName("xin.xyyanquan.sec.classloader.TestHelloWorld");
// ClassLoader加载TestHelloWorld示例
this.getClass().getClassLoader().loadClass("xin.xyyanquan.sec.classloader.TestHelloWorld");Class.forName("类名")默认会初始化被加载类的静态属性和方法,如果不希望初始化类可以使用Class.forName("类名", 是否初始化类, 类加载器),而ClassLoader.loadClass默认不会初始化类方法。
ClassLoader类加载流程
理解Java类加载机制并非易事,这里我们以一个Java的HelloWorld来学习ClassLoader。
ClassLoader加载com.anbai.sec.classloader.TestHelloWorld类loadClass重要流程如下:
ClassLoader会调用public Class<?> loadClass(String name)方法加载com.anbai.sec.classloader.TestHelloWorld类。调用
findLoadedClass方法检查TestHelloWorld类是否已经初始化,如果JVM已初始化过该类则直接返回类对象。如果创建当前
ClassLoader时传入了父类加载器(new ClassLoader(父类加载器))就使用父类加载器加载TestHelloWorld类,否则使用JVM的Bootstrap ClassLoader加载。如果上一步无法加载
TestHelloWorld类,那么调用自身的findClass方法尝试加载TestHelloWorld类。如果当前的
ClassLoader没有重写了findClass方法,那么直接返回类加载失败异常。如果当前类重写了findClass方法并通过传入的com.anbai.sec.classloader.TestHelloWorld类名找到了对应的类字节码,那么应该调用defineClass方法去JVM中注册该类。如果调用loadClass的时候传入的
resolve参数为true,那么还需要调用resolveClass方法链接类,默认为false。返回一个被JVM加载后的
java.lang.Class类对象。
示例 - ClassLoader#loadClass:
