一个简单程序的类加载流程

Aar*_*esh 63 java classloader

我刚刚开始学习Java的内部架构.我已经粗略地理解了类加载的概念,它在jvm运行时加载所需的类,ClassNotFoundException在没有找到类时抛出,特定的类加载器加载类引用的类.

有人可以清楚地解释类加载的流程,即下面的示例Java代码中的引导类加载和用户定义的类加载的顺序.

import java.io.File;
public class Sample
{
    public static void main(String[] args)
    {
        String fileName = "sample";
        File file = new File(fileName);
        file.isFile();
    }
} 
Run Code Online (Sandbox Code Playgroud)

我还从一个参考资料中学到了" classloader维护它加载的类的名称空间".通过名称空间,这是否意味着类的文字名称?也有人可以解释一下这个含义/优点吗?

San*_*osh 56

您将按Sample如下方式运行您的课程

> java Sample

对于小魔术,检查-verbose:class选项的输出,你会看到大量的以下行..

[Opened C:\jdk1.6.0_14\jre\lib\rt.jar]
[Loaded java.lang.Object from C:\jdk1.6.0_14\jre\lib\rt.jar]
[Loaded java.io.Serializable from C:\jdk1.6.0_14\jre\lib\rt.jar]
[Loaded java.lang.Comparable from C:\jdk1.6.0_14\jre\lib\rt.jar]
.
.
.
.
.
.
[Loaded java.security.cert.Certificate from C:\jdk1.6.0_14\jre\lib\rt.jar]
[Loaded Sample from file:/D:/tmp/]
[Loaded java.lang.Shutdown from C:\jdk1.6.0_14\jre\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from C:\jdk1.6.0_14\jre\lib\rt.jar]
Run Code Online (Sandbox Code Playgroud)

\jre\lib\rt.jar在类加载Bootstrap器(或Primordial)加载类之前,您会看到一堆类被加载.这些是运行任何由Bootstrap加载的Java程序的先决条件.

另一组jar由Extension类加载器加载.在这个特定的例子中,不需要lib中的任何类,\jre\lib\ext因此它没有被加载.但Extension类加载器专门分配了从扩展lib加载类的任务.

编辑:除了标准平台java类之外,Sun/Oracle还提供了一组用于扩展平台核心API的jar .放置在扩展lib文件夹中的jar自动放在类路径中,因此不需要显式地包含在类路径中.这是关于同一主题的好官方文章.

最后,在Bootstrap和Extension完成加载后,您的类SampleApplication类加载器加载.

  • @santosh +1提到`-verbose:class`选项. (15认同)

Nar*_*hai 50

类加载器层次结构

每当启动新的JVM时,引导类加载器都负责将关键Java类(从java.lang包)和其他运行时类首先加载到内存中.引导类加载器是所有其他类加载器的父级.因此,它是唯一没有父母的人.

接下来是扩展类加载器.它有bootstrap类加载器作为父类,负责从.jar保存在java.ext.dirs路径中的所有文件加载类- 无论JVM的类路径如何,它们都可用.

开发人员的角度来看,第三个也是最重要的类加载器是系统类路径类加载器,它是扩展类加载器的直接子代.它从CLASSPATH环境变量,java.class.path系统属性或-classpath命令行选项指定的目录和jar文件中加载类.

类加载器层次结构

ClassLoader命名空间

在Java中,使用唯一标识的类, ClassLoader + Class因为同一个类可以由两个不同的类加载器加载.

Class A loaded by ClassLoader A != Class A loaded by ClassLoader B
Run Code Online (Sandbox Code Playgroud)

它有什么用?

为不同的类加载器定义不同的保护和访问策略很有帮助.举一个使用不同类加载器加载的applet的例子,你不希望第三方应用程序访问你的资源.因此,对于安全性,维护不同名称空间非常重要.


Ani*_*kur 11

JVM在加载类的permgen区域中维护一个运行时池.每当引用类时,默认类加载器都会在类路径中找到该类并将其加载到此池中.这不是特定于JDK中提供的用户定义的类或类.引用类时,它将加载到内存中.

由ClassLoader加载的类内部存储在ClassLoader实例中

// The classes loaded by this class loader. The only purpose of this table
// is to keep the classes from being GC'ed until the loader is GC'ed.
private final Vector<Class<?>> classes = new Vector<>();
Run Code Online (Sandbox Code Playgroud)

当需要将类添加到内存后,调用以下函数:

// Invoked by the VM to record every loaded class with this loader.
void addClass(Class c) {
    classes.addElement(c);
}
Run Code Online (Sandbox Code Playgroud)

找到了有关类加载器如何工作的有用图表.

在此输入图像描述


rac*_*ana 6

Java虚拟机通过创建一个初始类,这是在一种实现依赖性方式的规定,使用引导类加载器(启动§5.3.1).然后,Java虚拟机链接初始类,初始化它和在其中声明的静态实例变量,最后调用公共类方法void main(String []).调用此方法会驱动所有进一步的执行.构成主方法的Java虚拟机指令的执行可以导致附加类和接口的链接(并因此创建),以及其他方法的调用.

阅读链接