5.2. Java Virtual Machine Startup
5.2 java虚拟机启动
The Java Virtual Machine starts up by creating an initial class, which is specified in an implementation-dependent manner, using the bootstrap class loader (§5.3.1). The Java Virtual Machine then links the initial class, initializes it, and invokes the public
class method void main(String[])
. The invocation of this method drives all further execution. Execution of the Java Virtual Machine instructions constituting the main
method may cause linking (and consequently creation) of additional classes and interfaces, as well as invocation of additional methods.
In an implementation of the Java Virtual Machine, the initial class could be provided as a command line argument. Alternatively, the implementation could provide an initial class that sets up a class loader which in turn loads an application. Other choices of the initial class are possible so long as they are consistent with the specification given in the previous paragraph.
java虚拟机启动是通过bootstrap类加载器通过创建一个初始化类完成的,这个类是由虚拟机的具体实现指定的。之后虚拟机会链接这个初始化类,初始化该类并且调用void main方法,这个方法的调用驱动了所有更深层次的调用。虚拟机执行的main方法指令会引起虚拟机链接额外的(其后创建的)一些接口或者类,也会调用一些额外的方法。
在虚拟机的实现中,初始化类可能会被提供给虚拟机作为一个命令行参数。或者这个虚拟机的实现可能会提供一个初始化类设置一个类加载器用于加载应用。或者在遵循之前给出的规范的前提下虚拟机实现也可能会用其他类加载器。
5.3. Creation and Loading
5.3 创建和加载
Creation of a class or interface C denoted by the name N
consists of the construction in the method area of the Java Virtual Machine (§2.5.4) of an implementation-specific internal representation of C. Class or interface creation is triggered by another class or interface D, which references Cthrough its run-time constant pool. Class or interface creation may also be triggered by D invoking methods in certain Java SE platform class libraries (§2.12) such as reflection.
If C is not an array class, it is created by loading a binary representation of C (§4 (The class
File Format)) using a class loader. Array classes do not have an external binary representation; they are created by the Java Virtual Machine rather than by a class loader.
There are two kinds of class loaders: the bootstrap class loader supplied by the Java Virtual Machine, and user-defined class loaders. Every user-defined class loader is an instance of a subclass of the abstract class ClassLoader
. Applications employ user-defined class loaders in order to extend the manner in which the Java Virtual Machine dynamically loads and thereby creates classes. User-defined class loaders can be used to create classes that originate from user-defined sources. For example, a class could be downloaded across a network, generated on the fly, or extracted from an encrypted file.
A class loader L
may create C by defining it directly or by delegating to another class loader. If L
creates C directly, we say that L
defines C or, equivalently, that L
is the defining loader of C.
When one class loader delegates to another class loader, the loader that initiates the loading is not necessarily the same loader that completes the loading and defines the class. If L
creates C, either by defining it directly or by delegation, we say that L
initiates loading of C or, equivalently, that L
is an initiating loader of C.
如果要创建标记为N的类或者标记为C的类,需要现在java虚拟机的方法区上为c创建于虚拟机实现相匹配的内部表示。c的创建是由另外一个类或者接口D所触发的。他们通过自己的运行时常量池引用了C,当然C的创建也可能是由D调用javaSE平台类库中的某些方法触发,例如反射。
如果C不是数组类,那么它可以用过类加载器加载c的二进制表示来创建。数组类没有外部的二进制表示,他们都是由java虚拟机创建的,而不是通过类加载器加载的。
java虚拟机支持两种类加载器:java虚拟机提供的引导类加载器和用户自定义的类加载器
每个用户自定义的类加载器都应该是抽象类Classloader的某个子类的实例。
应用程序使用用户自己定义的类加载器是为了便于扩展java虚拟机的功能,以支持动态加载并创建类。当然它也可以从用户自定义的数据来源获取类的二进制表示并创建类。例如用户自定义类加载器可以通过网络下载动态的产生或从一个加密文件中提取类的信息。
类加载器L可能会通过直接定义或者委托其他类加载器创建C。如果L直接创建C,就可以说L定义了C,或者L是C的定义加载器。
当一个类加载器把加载请求委托给其他的类加载器后,发出这个加载请求的加载器 与 最终完成加载并定义类的类加载器不需要是同一个加载器。如果L创建了C 那么它可能是通过直接定义的方式或者委托给其他加载器的方式创建的C,可以说L初始化C的加载或者L是C的初始化加载器。
At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (§4.2.1) and its defining class loader. Each such class or interface belongs to a single run-time package. The run-time package of a class or interface is determined by the package name and defining class loader of the class or interface.
The Java Virtual Machine uses one of three procedures to create class or interface C denoted by N
:
-
If
N
denotes a nonarray class or an interface, one of the two following methods is used to load and thereby create C: -
Otherwise
N
denotes an array class. An array class is created directly by the Java Virtual Machine (§5.3.3), not by a class loader. However, the defining class loader of D is used in the process of creating array class C.
在java虚拟机运行时 类或者接口不仅仅被他的名字决定,而是由一个键值对确定:二进制名称和他的定义类加载器共同确定。每一个这样的类或者接口都只属于一个运行时包。类或者接口的运行时包结构由包名及类或者接口的定义类加载器决定。
java虚拟机通过下面三个过程之一来创建类N或者接口C
1、如果N表示一个非数组的类或接口,那么可以用下面两种方式来创建加载C
1.1如果D是由(bootstrap 加载器)引导类加载器所定义的,那么用引导类加载器加载C
1.2如果D是由用户自定义加载的,那么可以用用户自定义类加载器加载C
2、如果N是一个数组类,那么该数组类是由java虚拟机而不是类加载器创建的。然而在创建数组类C的过程中,也会用D的定义类加载器。
If an error occurs during class loading, then an instance of a subclass of LinkageError
must be thrown at a point in the program that (directly or indirectly) uses the class or interface being loaded.
If the Java Virtual Machine ever attempts to load a class C during verification (§5.4.1) or resolution (§5.4.3) (but not initialization (§5.5)), and the class loader that is used to initiate loading of C throws an instance of ClassNotFoundException
, then the Java Virtual Machine must throw an instance of NoClassDefFoundError
whose cause is the instance of ClassNotFoundException
.
(A subtlety here is that recursive class loading to load superclasses is performed as part of resolution (§5.3.5, step 3). Therefore, a ClassNotFoundException
that results from a class loader failing to load a superclass must be wrapped in a NoClassDefFoundError
.)
如果加载过程中产生错误那么某个LinkageError的子类的实例必须被抛出,抛出位置应该是用到了当前正在加载进来的类或者接口的那个地方。
如果java虚拟机试图在验证或者解析但还没有初始化时加载C类,用于加载C类的初始化类加载器抛出了ClassNotFoundException类,那么Java虚拟机必须抛出NoClassDefFoundError异常,他的cause字段中保存了ClassNotFoundException实例。
这里有个地方需要注意作为解析的一部分,类加载器会递归加载它的父类。如果类加载器在加载父类的时候因为失败而产生ClassNotFoundException异常,那么该异常必须包装在NoClassDefFoundError异常中。
A well-behaved class loader should maintain three properties:
-
Given the same name, a good class loader should always return the same
Class
object. -
If a class loader
L1
delegates loading of a class C to another loaderL2
, then for any type T that occurs as the direct superclass or a direct superinterface of C, or as the type of a field in C, or as the type of a formal parameter of a method or constructor in C, or as a return type of a method in C,L1
andL2
should return the sameClass
object. -
If a user-defined classloader prefetches binary representations of classes and interfaces, or loads a group of related classes together, then it must reflect loading errors only at points in the program where they could have arisen without prefetching or group loading.
一个好的类加载器应有下面三个属性
1、给定相同的名称,类加载器返回相同的class对象
2、如果类加载器L1将加载C类的请求交给L2加载器,那么对于满足下列条件之一的任意类型T来说,L1和L2都应当返回相同的Class对象。
2.1 T是C的直接柴磊或者直接超接口;
2.2 T是C中某个字段的类型;
2.3 T是C中某个方法或者构造器的形式参数类型;
2.4 T是C中某个方法的返回值类型。
3、如果某个用户自定义的类加载器预先加载了某个类或者接口的二进制表示,或者批量的加载了一组相关的类,并在加载时出现错误,那他就必须在程序的某个点反应出加载时的错误。而这个点一定要和不使用预先加载或者批量加载时出现错误的那个点相同。