被final修饰的类,不允许被继承

类加载过程

image.png

类加载器

image.png

双亲委派模型

image.png

双亲委派机制的好处:避免类的重复加载

双亲委派模型保证了Java程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。 如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类。

自定义类加载器

除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。如果我们要自定义自己的类加载器,很明显需要继承 ClassLoader

谈到类加载器,绕不过的一个话题是自定义类加载器。使用自定义类加载器的常见场景有:

  • 实现类似进程内隔离,类加载器实际上用作不同的命名空间,以提供类似容器、模块化的效果。例如,两个模块依赖于某个类库的不同版本,如果分别被不同的容器加载,就可以互不干扰。这个方面的集大成者是Java EE和OSGI、JPMS等框架。
  • 应用需要从不同的数据源获取类定义信息,例如网络数据源,而不是本地文件系统。
  • 或者是需要自己操纵字节码,动态修改或者生成类型。

我们可以总体上简单理解自定义类加载过程:

  • 通过指定名称,找到其二进制实现,这里往往就是自定义类加载器会“定制”的部分,例如,在特定数据源根据名字获取字节码,或者修改或生成字节码。
  • 然后,创建 Class 对象,并完成类加载过程。二进制信息到 Class 对象的转换,通常就依赖defineClass,我们无需自己实现,它是 final 方法。有了 Class 对象,后续完成加载过程就顺理成章了。

自定义一个类加载器
java-classloaders-baeldung
Tomcat源码解剖-自定义类加载器