一个简单的程序的类加载stream程
我刚刚开始学习Java的内部架构。 我大致了解了类加载的概念,它在jvm
运行时加载所需的类,当没有find类时,抛出ClassNotFoundException
并且特定的类加载器加载类引用的类。
有人可以请清楚地解释类加载的stream程,即在下面的示例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
维护它所加载的类的名字空间”。 通过命名空间,这是否意味着类的字面名称? 也有人可以解释的含义/优势呢?
你将运行你的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
的任何类,因此它没有被加载。 但是扩展类加载器专门分配了从扩展库中加载类的任务。
编辑:除了标准平台Java类Sun / Oracle还提供了一组用于扩展平台核心API的jar。 放置在扩展lib文件夹中的jar自动放置在classpath中,因此不需要显式地包含在classpath中。 这里是关于同一主题的不错的官方文章 。
最后,在Bootstrap和Extension加载完成后,你的类Sample
被Application
class loader加载。
类加载器层次结构
每当启动一个新的JVM时,引导类加载器负责将关键Java类(从java.lang
包)和其他运行时类加载到内存中。 引导类加载器是所有其他类加载器的父代。 因此,这是唯一没有父母的人。
接下来是扩展类加载器。 它具有引导类加载器作为父类,负责从保存在java.ext.dirs
path中的所有.jar
文件中加载类 – 不pipeJVM的类path如何,这些文件都是可用的。
从开发人员的angular度来看 ,第三个也是最重要的类加载器是系统类path类加载器,它是扩展类加载器的直接子节点。 它从CLASSPATH
环境variablesjava.class.path
系统属性或-classpath
命令行选项指定的目录和jar文件中加载类。
ClassLoader命名空间
在Java中,使用ClassLoader + Class
来唯一标识一个类,因为同一个类可能由两个不同的类加载器加载。
Class A loaded by ClassLoader A != Class A loaded by ClassLoader B
它有什么用?
为不同的类加载器定义不同的保护和访问策略是有帮助的。 以一个使用不同类加载器加载的applet为例,您不希望第三方应用程序全部访问您的资源。 所以对于安全来说,维护不同的命名空间非常重要。
JVM维护运行时池是加载类的permgen区域。 每当一个类被引用,defualt类加载器发现类是类path,并将其加载到此池中。 这不是特定于JDK中提供的用户定义的类或类。 当引用它的类ID被加载到内存中。
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); }
findClass Loaders如何工作的有用图表。
Java虚拟机通过使用引导类加载器(第5.3.1节 )创build初始类来启动,该初始类以实现相关的方式指定。 Java虚拟机然后链接初始类,初始化它和在其中声明的静态实例variables,最后调用公共类方法void main(String []) 。 这个方法的调用驱动所有进一步的执行。 构成主要方法的Java虚拟机指令的执行可能会导致附加的类和接口的链接(以及相应的创build),以及调用附加的方法。
阅读这个链接
加载过程可以看作类加载器子系统和JVM的内存区之间的交互。
类加载器的工作原理有三个步骤:1.加载2.)链接和3.)初始化。
类加载器子系统和内存区域之间非常基本的交互发生在链接 (除了其他交互!
链接活动细分为i)validationii。)准备和iii)解决。 validation:更安全,检查有效的编译。 在步骤ii)中准备 – 静态variables存储器被分配并分配有默认值。 而且,
iii)parsing:符号引用被replace为来自“方法区域”的原始引用,其中包含类级别的数据和静态variables。
JVM Arch