为什么 getConstructor 反射需要 int.class 参数 api?

Why int.class argument required with getConstructor reflection api?

Class 实例在每个类型的常量池中创建,当特定的 class(X) 被加载时。

javac 编译此语法 int.class 以指向 Integer.TYPE 指向的对象。

在代码下方,可以访问 class X.

的 parameterise(int) 构造函数
Class c = X.class;
Constructor cons = c.getConstructor(int.class);
cons.newInstance(10);

在上面的代码中,我没有理解 int.class 参数的作用,在幕后。

为什么 getConstructor 没有设计为接受 String 类型参数 "int" 而不是 int.classClass.forName() 的论点就是一个例子。

int.class 而不是 Integer.TYPE 是 java 编译器替代的语法糖。一个 Class 对象简单地说,一个对象保存关于代码内部结构的元信息。但如果我们对此采取更抽象的观点,我们可以重用 class 来表示 typesprimitives,interfaces,甚至 void -这不是类型,而是具有 no return value 的方法的标识符。 Class 的这种重用在您的示例中有很多优点;考虑以下代码:

public class X {
    public static void main(String args[]) throws Exception {
        X myX = X.class.getConstructor().newInstance();
        X myBigX = X.class.getConstructor(Integer.class).newInstance(0xCEED);
        X mySmallX = X.class.getConstructor(int.class).newInstance(10);
    }

    public X() {
        System.out.println("parameterless constructor called");
    }

    public X(Integer bigInteger) {
        System.out.println("object integer constructor called");
    }

    public X(int smallInteger) {
        System.out.println("primitive integer constructor called");
    }
}

如果反射 API 开发人员为每个方法引入了 Class 对象作为类型标识符,则必须引入第二个方法来处理不完全 classes 的类型这会造成不必要的代码重复和不灵活。现在,为什么他们决定将 .class 附加到原始类型关键字以引用各自的 Class 指针?正如一些人已经说过的那样,省略该部分会导致进一步的混乱和语法错误。事实上,后缀只是延续了写硬编码类型的模式。

首先,Class是一种专用于某种目的的类型。有很多 类,我们可以简单地用 String 替换它们的实例,如果我们接受一点歧义和可能的性能损失,它就会起作用。例如。为什么使用数字而不是 Strings 包含他们的代表,或者为什么使用 enums 而不是他们的名字?因此,拥有专用类型的实例可确保已成功执行创建、查找、解析或获取该实例所需的任何操作。

所以有一个 Class 对象代表 int.class,你知道你指的是一个现有的类型,你不能说 String "int" . String 参数不一定引用现有类型——它甚至不必包含有效名称。如果您查找具有两个 int 参数的构造函数,传递 "int", "int" 将意味着完成验证正确性和两次查找适当类型的整个工作。等等……

而且,由于 Java 编程语言的限制不适用于 JVM,因此 String 是不明确的。不清楚 "int" 是指一个名为 intclass 还是原始类型 int。请注意,当您在 ClassLoader 上调用 loadClass("int") 时,始终假定您指的是名为 intclass,因为该方法不适合查找基本类型.这就是为什么 int.class 被编译为访问 Integer.TYPE 的原因,因为原始类型不能像引用类型一样被查找。

此外,正如已经解释过的 ,名称在运行时是不明确的,因为可以有多个 类 具有相同的名称,由不同的 ClassLoader 定义。

JVMS §5.3 “Creation and Loading”:

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.

还有JLS §12.2 “Loading of Classes and Interfaces”

Well-behaved class loaders maintain these 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 loader L2, 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 and L2 should return the same Class object.

A malicious class loader could violate these properties. However, it could not undermine the security of the type system, because the Java Virtual Machine guards against this.