Varargs-Constructor 不能使用反射充当默认构造函数
Varargs-Constructor cannot act as default constructor using reflection
FXML 视图:
....
<GridPane...>
<PersonController... />
</GridPane...>
....
Class 个人控制器:
public PersonController(Person... personsToExclude) {
FXMLLoader.load("PersonControllerView.fxml")
this.personsToExclude = personsToExclude;
}
此代码示例导致异常,因为 class 无法在没有默认构造函数(由 FXMLLoader)的情况下调用。现在我的问题是:您可以将此构造函数用作默认构造函数。您可以像这样创建这样一个对象:
PersonConstructor pc = new PersonConstructor(); // This calls the upper constructor
为什么反射不能也使用这个构造函数? Varargs 似乎是内部数组,如果没有传递参数,默认情况下将为 null。
这个设计决定仅仅是为了降低复杂性(它实际上确实为 reader 降低了一点)还是有任何其他原因为什么仍然有一个 "real" 很重要默认构造函数?
如果 Oliver Charlesworth 是正确的,那么您的问题确实是:
Why doesn't Class#newInstance()
work when the class doesn't have a zero-args constructor but does have a constructor accepting a single varargs argument?
如果是这样,我认为我们无法正确回答它,除非在设计过程中引用了将可变参数添加到 Java.
我们可以推测。我的推测是:Simplicity
newInstance()
比可变参数早。在可变参数被添加到语言中之前,没有歧义:它只能调用 nullary(零参数)构造函数。所以他们可能觉得扩展它以处理接受一个可变参数参数的构造函数是该方法的代码膨胀 and/or 范围蔓延。毕竟,如果你真的想这样做,你可以查找相关的构造函数并调用它。
或者,他们可能觉得 newInstance
的文档排除了调用此类构造函数的可能性。让我们看看 JavaDoc for newInstance()
:
Creates a new instance of the class represented by this Class object. The class is instantiated as if by a new expression with an empty argument list. The class is initialized if it has not already been initialized.
Note that this method propagates any exception thrown by the nullary constructor, including a checked exception...
第一段支持这样的想法,即它可以仅使用一个可变参数调用构造函数。但是,第二段特别提到了 "nullary" 构造函数(尽管是顺便说一句)。 "nullary" 构造函数是零参数构造函数,具体来说,不仅仅是 可以 不带参数调用的构造函数。
这样做会使 newInstance()
明显复杂化,因为它需要遍历所有构造函数来寻找接受单个参数的构造函数,而不是仅仅寻找一个不接受任何参数的构造函数其中 isVarArgs
为真。
更改 newInstance()
以执行您建议的操作会添加一个新的错误模式:您的 PersonConstructor
class 完全有可能 可以通过 new PersonConstructor()
:
调用多个 构造函数
public class PersonConstructor
{
public PersonConstructor(String... args) {
}
public PersonConstructor(Person... args) {
}
}
那么 newInstance
应该给哪一个打电话呢?它不能决定,所以它必须抛出,抛出一个在向语言添加可变参数之前没有抛出的新错误。
总而言之,如果我在做出决定的团队中,我也会 newInstance()
只考虑真正的 nullary 构造函数,而不是接受单个可变参数参数的构造函数。 (我也会更新 JavaDoc 来说明这一点。:-))
可变参数列表完全在编译器中实现。采用数组的方法和采用可变参数数组的方法彼此兼容 - 例如,您可以使用可变参数签名
void foo(String... args)
覆盖非可变参数签名
void foo(String[] args)
反之亦然 (demo)。
Was this design decision solely made to reduce complexity?
很难猜测为什么做出了这个特定的设计决定,但至少部分原因可以归因于设计者不愿对库和 JVM 进行更改。 Java 5 更新,其中引入了可变参数功能,选择了字节码级别的完全向后兼容性,尽管这是一个非常大的更新,它引入了泛型。
如果您想解决此限制,请实现一个无参数构造函数,将调用路由到采用数组的构造函数:
public PersonController(Person... personsToExclude) {
}
public PersonController() {
this(new Person[0]);
}
Varargs appear to be arrays internally which will be null by default if no parameter was handed over.
这不是真的。如果您调用不带任何参数的可变参数方法(或构造函数),该方法(或构造函数)仍然是具有一个数组参数的方法。正如 Oliver 已经指出的那样,不会传递 null,而是一个空数组。
所以答案是:可变参数构造函数肯定只有一个参数,因此它不能是默认构造函数。
FXML 视图:
....
<GridPane...>
<PersonController... />
</GridPane...>
....
Class 个人控制器:
public PersonController(Person... personsToExclude) {
FXMLLoader.load("PersonControllerView.fxml")
this.personsToExclude = personsToExclude;
}
此代码示例导致异常,因为 class 无法在没有默认构造函数(由 FXMLLoader)的情况下调用。现在我的问题是:您可以将此构造函数用作默认构造函数。您可以像这样创建这样一个对象:
PersonConstructor pc = new PersonConstructor(); // This calls the upper constructor
为什么反射不能也使用这个构造函数? Varargs 似乎是内部数组,如果没有传递参数,默认情况下将为 null。
这个设计决定仅仅是为了降低复杂性(它实际上确实为 reader 降低了一点)还是有任何其他原因为什么仍然有一个 "real" 很重要默认构造函数?
如果 Oliver Charlesworth 是正确的,那么您的问题确实是:
Why doesn't
Class#newInstance()
work when the class doesn't have a zero-args constructor but does have a constructor accepting a single varargs argument?
如果是这样,我认为我们无法正确回答它,除非在设计过程中引用了将可变参数添加到 Java.
我们可以推测。我的推测是:Simplicity
newInstance()
比可变参数早。在可变参数被添加到语言中之前,没有歧义:它只能调用 nullary(零参数)构造函数。所以他们可能觉得扩展它以处理接受一个可变参数参数的构造函数是该方法的代码膨胀 and/or 范围蔓延。毕竟,如果你真的想这样做,你可以查找相关的构造函数并调用它。或者,他们可能觉得
newInstance
的文档排除了调用此类构造函数的可能性。让我们看看 JavaDoc fornewInstance()
:Creates a new instance of the class represented by this Class object. The class is instantiated as if by a new expression with an empty argument list. The class is initialized if it has not already been initialized.
Note that this method propagates any exception thrown by the nullary constructor, including a checked exception...
第一段支持这样的想法,即它可以仅使用一个可变参数调用构造函数。但是,第二段特别提到了 "nullary" 构造函数(尽管是顺便说一句)。 "nullary" 构造函数是零参数构造函数,具体来说,不仅仅是 可以 不带参数调用的构造函数。
这样做会使
newInstance()
明显复杂化,因为它需要遍历所有构造函数来寻找接受单个参数的构造函数,而不是仅仅寻找一个不接受任何参数的构造函数其中isVarArgs
为真。更改
调用多个 构造函数newInstance()
以执行您建议的操作会添加一个新的错误模式:您的PersonConstructor
class 完全有可能 可以通过new PersonConstructor()
:public class PersonConstructor { public PersonConstructor(String... args) { } public PersonConstructor(Person... args) { } }
那么
newInstance
应该给哪一个打电话呢?它不能决定,所以它必须抛出,抛出一个在向语言添加可变参数之前没有抛出的新错误。
总而言之,如果我在做出决定的团队中,我也会 newInstance()
只考虑真正的 nullary 构造函数,而不是接受单个可变参数参数的构造函数。 (我也会更新 JavaDoc 来说明这一点。:-))
可变参数列表完全在编译器中实现。采用数组的方法和采用可变参数数组的方法彼此兼容 - 例如,您可以使用可变参数签名
void foo(String... args)
覆盖非可变参数签名
void foo(String[] args)
反之亦然 (demo)。
Was this design decision solely made to reduce complexity?
很难猜测为什么做出了这个特定的设计决定,但至少部分原因可以归因于设计者不愿对库和 JVM 进行更改。 Java 5 更新,其中引入了可变参数功能,选择了字节码级别的完全向后兼容性,尽管这是一个非常大的更新,它引入了泛型。
如果您想解决此限制,请实现一个无参数构造函数,将调用路由到采用数组的构造函数:
public PersonController(Person... personsToExclude) {
}
public PersonController() {
this(new Person[0]);
}
Varargs appear to be arrays internally which will be null by default if no parameter was handed over.
这不是真的。如果您调用不带任何参数的可变参数方法(或构造函数),该方法(或构造函数)仍然是具有一个数组参数的方法。正如 Oliver 已经指出的那样,不会传递 null,而是一个空数组。
所以答案是:可变参数构造函数肯定只有一个参数,因此它不能是默认构造函数。