“新”是什么在Java w.r.t.做类加载器? [英] What does "new" do in Java w.r.t. class loader?

查看:124
本文介绍了“新”是什么在Java w.r.t.做类加载器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不能在JLS / JVMSpec中找到它,也不能在SO中找到它。我肯定一定会被问到......

I cannot easily find it in JLS/JVMSpec, nor in SO. I'm sure it must've been asked...

那么,新究竟做了什么?假设我们在A中实例化一个B类:

So, what does "new" do actually? Suppose we instantiate a class B in A:

class A {
    // ...
    new B();
    // ...
}

这相当于

class A {
    // ...
    A.class.getClassLoader().loadClass("B's canonical name").newInstance();
    // ...
}

在每个环境中都是这样,还是不是那样?

Does it, or does it not work like that in every environment?

如果你能指出我的话,我将不胜感激JLS / JVMSpec中的相应章节。谢谢!

I'd be grateful if you can point me to the appropriate chapter in JLS/JVMSpec. Thanks!

编辑:我们肯定无法在<$ c $中调用 B.class.getCanonicalName() c> loadClass()调用,因为B尚未加载。 JVM必须根据import语句解析名称。

surely we can't call B.class.getCanonicalName() in loadClass() call, since B's not loaded yet. JVM has to resolve the name based on the import statement.

推荐答案


这相当于

Is this equivalent to

class A {
    // ...
    A.class.getClassLoader().loadClass("B's canonical name").newInstance();
    // ...
}

不,并非总是如此。

类加载仅对给定的命名空间执行一次,除非先前已卸载 Class 。因此,在大多数情况下,等效表达式 A.class.getClassLoader()。loadClass(B的规范名称)将只执行一次。换句话说,如果你有两个表达式 - new A() loadClass 将只执行一次。

Class loading is performed only once for a given namespace, unless the Class in question has been previously unloaded. Therefore, the equivalent expression A.class.getClassLoader().loadClass("B's canonical name") will be executed only once in most scenarios. In other words, if you have two expressions - new A(), the loadClass will be performed only once.

构造函数的调用被JVM视为方法调用,但这需要Java编译器的配合。 JVM和编译器必须遵守Java虚拟机规范的第3.9节,其中规定:

Invocation of a constructor is treated as a method invocation by the JVM, but this requires the cooperation of a Java compiler. The JVM and the compiler have to adhere to section 3.9 of the Java Virtual Machine Specification, which states:


3.9特别命名的初始化方法

在Java虚拟机级别,每个构造函数(§2.12)
都显示为具有特殊名称的实例初始化方法
< init> 。该名称由编译器提供。因为名称< init>
不是有效的标识符,所以不能直接在用Java编程语言编写的程序
中使用它。实例初始化
方法只能通过
invokespecial 指令在Java虚拟机中调用,并且只能在
未初始化的类实例上调用它们。实例初始化方法在构造函数的访问权限(第2.7.4节)上花费
,从中获取

At the level of the Java virtual machine, every constructor (§2.12) appears as an instance initialization method that has the special name <init>. This name is supplied by a compiler. Because the name <init> is not a valid identifier, it cannot be used directly in a program written in the Java programming language. Instance initialization methods may be invoked only within the Java virtual machine by the invokespecial instruction, and they may be invoked only on uninitialized class instances. An instance initialization method takes on the access permissions (§2.7.4) of the constructor from which it was derived.

一个类或者接口最多只有一个类或接口初始化
方法,并通过调用该方法进行初始化(第2.17.4节)。类或接口的
初始化方法是静态的,不带
参数。它具有特殊名称< clinit> 。该名称由
编译器提供。因为名称< clinit> 不是有效的标识符,所以
不能直接用于用Java编程
语言编写的程序中。 Java虚拟机隐式调用类和接口初始化方法
;它们永远不会直接从任何Java虚拟机指令调用
,但仅作为类初始化过程的一部分间接调用

A class or interface has at most one class or interface initialization method and is initialized (§2.17.4) by invoking that method. The initialization method of a class or interface is static and takes no arguments. It has the special name <clinit>. This name is supplied by a compiler. Because the name <clinit> is not a valid identifier, it cannot be used directly in a program written in the Java programming language. Class and interface initialization methods are invoked implicitly by the Java virtual machine; they are never invoked directly from any Java virtual machine instruction, but are invoked only indirectly as part of the class initialization process.

本节假定当前线程可以使用与该类相关的 Class 对象。一旦 Class 对象可用,方法< init> 对应于具有正确参数集的构造函数,将被调用。

This section assumes that the Class object pertaining to the class in question is available to the current thread. Once the Class object is available, the method <init> corresponding to the constructor with the right set of arguments, will be invoked.

如果尚未加载类,将使用哪个类加载器加载类的问题有点不同,与新的无关关键词。它取决于一个类如何引用另一个类,即需要在运行时常量池中解析符号引用?此上下文中的行为在Java虚拟机规范的第5.3节中定义:

The question of which classloader will be used to load the class, if not already loaded, is a bit different, and has nothing to do with the new keyword. It depends on how one class references another i.e. does a symbolic reference need to be resolved in the runtime constant pool? The behavior in this context is defined in Section 5.3 of the Java Virtual Machine Specification:


5.3创建和加载

创建一个由名称N表示的类或接口C由
构成Java虚拟机的方法区域中的构造
(§ 3.5.4)C的特定于实现的内部表示形式。
类或接口创建由另一个类或接口
D触发,它通过其运行时常量池引用C.

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 (§3.5.4) of an implementation-specific internal representation of C. Class or interface creation is triggered by another class or interface D, which references C through its runtime constant pool.

...

Java虚拟机使用以下三个过程之一来创建类
或由N表示的接口C:

The Java virtual machine uses one of three procedures to create class or interface C denoted by N:


  • 如果N表示非阵列类或接口,则使用以下两种方法之一来加载,从而创建C:

  • If N denotes a nonarray class or an interface, one of the two following methods is used to load and thereby create C :


  • 如果D是由bootstrap类加载器定义的,那么bootstrap
    类加载器initi加载C(§5.3.1)。

  • If D was defined by the bootstrap class loader, then the bootstrap class loader initiates loading of C (§5.3.1).

如果D是由用户定义的类加载器定义的,那么同样的
用户 - 定义的类加载器启动加载C(第5.3.2节)。

If D was defined by a user-defined class loader, then that same user-defined class loader initiates loading of C (§5.3.2).

否则N表示数组类。数组类由Java虚拟机(第5.3.3节)直接创建,而不是由类加载器创建。
但是,D的定义类加载器在
创建数组类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.

注意句子 - 如果D是由用户定义的类加载器定义的,那么同一个用户定义的类加载器会启动加载C 在上面的引用中。在表达式 new A()的上下文中,加载封闭类的类加载器将负责加载 A 按照VM Spec;这当然是假设引导类加载器没有加载封闭类。

Note the sentence - If D was defined by a user-defined class loader, then that same user-defined class loader initiates loading of C in the above quote. In the context of the expression new A(), the classloader that loaded the enclosing class will be responsible for loading A in accordance with the VM Spec; this is of course, assuming that the enclosing class is not loaded by the bootstrap classloader.

这篇关于“新”是什么在Java w.r.t.做类加载器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆