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

时间:2013-12-27 06:35:52

标签: 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();
    }
} 

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

5 个答案:

答案 0 :(得分:55)

您将按如下方式运行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]

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

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

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

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

答案 1 :(得分:50)

Classloader hierarchy

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

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

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

Classloader hierarchy

ClassLoader命名空间

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

Class A loaded by ClassLoader A != Class A loaded by ClassLoader B
  

它有什么用?

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

答案 2 :(得分: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<>();

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

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

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

enter image description here

答案 3 :(得分:6)

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

阅读this链接

答案 4 :(得分:1)

  

加载过程可以视为Classloader之间的交互   子系统和JVM的内存区域。

类加载器的工作原理分为三个步骤:1)加载2.)链接和3.)初始化。

  

Classloader子系统和它之间非常基本的交互   记忆区域在链接期间发生(除了其他交互!)

链接活动细分为i。)验证ii。)准备和iii。)解决。 验证:更多的是安全性,检查有效的编译。在步骤ii。)准备 - 分配静态变量存储器并分配默认值。 并在

  

iii。)解决:符号引用被替换为原始   参考来自&#34;方法区&#34;其中包含类级数据和   静态变量。

JVM Arch