Varargs-Constructor不能使用反射作为默认构造函数

时间:2015-12-27 11:04:56

标签: java reflection javafx variadic-functions default-constructor

FXML - 视图:

....
    <GridPane...>
        <PersonController... />
    </GridPane...>
....

Class PersonController:

public PersonController(Person... personsToExclude) {
    FXMLLoader.load("PersonControllerView.fxml")
    this.personsToExclude = personsToExclude;
}

此代码示例导致excpetion,因为如果没有默认构造函数(由FXMLLoader),则无法调用该类。现在我的问题:您可以使用此构造函数作为默认构造函数。您可以创建这样的对象:

PersonConstructor pc = new PersonConstructor(); // This calls the upper constructor

为什么反射也不能使用这个构造函数呢? Varargs似乎是内部的数组,如果没有参数被移交,默认情况下它将为null。

这个设计决策是否仅仅是为了降低复杂性(实际上它确实为读者减少了一点),还是有其他原因使得仍然拥有“真正的”默认构造函数很重要?

3 个答案:

答案 0 :(得分:2)

如果奥利弗查尔斯沃思是正确的,你的问题确实是:

  

当类没有零参数构造函数但是构造函数接受单个varargs参数时,为什么Class#newInstance()不起作用?

如果是这样,我认为我们不能正确回答它,除非在设计过程中引用了关于向Java添加varargs的内容。

我们可以推测。我的推测是: 简单

  1. newInstance()比varargs年龄大。在将varargs添加到语言之前,没有歧义:它只能调用nullary(零参数)构造函数。所以他们可能觉得扩展它以处理接受一个varargs参数的构造函数是该方法的代码膨胀和/或范围蠕变。毕竟,如果你真的想这样做,你可以查找相关的构造函数并调用它。

  2. 或者,他们可能觉得newInstance的文档排除了调用这样的构造函数。我们来看看JavaDoc for newInstance()

      

    创建此Class对象表示的类的新实例。该类实例化为具有空参数列表的新表达式。如果尚未初始化,则初始化该类。

         

    请注意,此方法传播由Nullary构造函数抛出的任何异常,包括已检查的异常......

    第一段支持这样的想法,它只能用一个varargs参数调用构造函数。但是,第二段特别提到了一个“无效”构造函数(虽然顺便说一下)。 “nullary”构造函数是一个零参数构造函数,具体而言,不仅仅是一个可以无需参数调用的构造函数。

  3. 这样做会使newInstance()显着复杂化,因为它不仅仅是寻找不接受任何参数的构造函数,而是需要查看接受单个参数的所有构造函数,其中{{3是真的。

  4. 更改newInstance()以执行您建议的操作会添加新的错误模式:您的PersonConstructor类完全有可能拥有多个构造函数可以通过new PersonConstructor()调用:

    public class PersonConstructor
    {
        public PersonConstructor(String... args) {
        }
    
        public PersonConstructor(Person... args) {
        }
    }
    

    那个人应该newInstance打电话给谁?它无法决定,所以它必须抛出,抛出一个新的错误,它在向语言添加varargs之前没有抛出。

  5. 总而言之,如果我在团队中做出决定,我也会让newInstance()只考虑真正的nullary构造函数而不是构造函数接受单个varargs参数。 (我也会更新JavaDoc来说明。:-))

答案 1 :(得分:1)

变量参数列表完全在编译器中实现。采用vararg数组的数组和方法的方法是相互兼容的 - 例如,你可以使用vararg签名

void foo(String... args)

覆盖非vararg签名

void foo(String[] args)

,反之亦然(demo)。

  

这个设计决定是否仅仅是为了降低复杂性?

很难猜出为什么做出这个特定的设计决定,但至少部分原因可归因于设计师不愿意对库和JVM进行更改。 Java 5更新(其中引入了变量参数功能)选择了字节码级别的完全向后兼容性,尽管它是一个非常大的更新,它引入了泛型。

如果您想要解决此限制,请实现一个无参数构造函数,该构造函数将调用带有数组的构造函数的路径:

public PersonController(Person... personsToExclude) {
}
public PersonController() {
    this(new Person[0]);
}

答案 2 :(得分:0)

  

Varargs似乎是内部的数组,如果没有移交任何参数,默认为null。

事实并非如此。如果在没有任何参数的情况下调用vararg方法(或构造函数),则方法(或构造函数)仍然是具有一个数组参数的方法。并且不会传递null,而是一个空数组,正如Oliver已经指出的那样。

所以答案是:vararg构造函数肯定有一个参数,因此它不能是默认的构造函数。