具有可变参数参数的多个构造函数
Multiple constructors with variable argument parameters
给定这两个构造函数:
SomeClass(int... params)
{
// Do things
}
SomeClass(long... otherParams)
{
// Do other things
}
实例化对象 foo 时会发生什么?
SomeClass foo = new SomeClass();
是否以某种方式调用了未定义的默认构造函数?或者是那些调用了空数组的构造函数之一?如果有,有什么先例?
我做了一些基本测试,发现如果定义了一个没有参数的构造函数,那么它就会被调用。否则,出现调用不明确
根据 this very good answer in "Varargs in method overloading in Java" question below are the rules used by Java compiler for selecting the method signature to invoke. They are based on JLS 5.3. Method Invocation Conversion 文档。
- 基元加宽使用尽可能小的方法参数
- Wrapper 类型不能扩展为另一种 Wrapper 类型
- 您可以将 Box 从 int 变为 Integer 并扩大到
Object
但不能扩大到 Long
- 加宽胜过 Boxing,Boxing 胜过 Var-args。
- 你可以先装箱然后加宽(一个
int
可以通过Integer
变成Object
)
- 你不能加宽然后加框(一个
int
不能变成Long
)
- 您不能将可变参数与加宽或装箱结合使用
因为两个构造函数都是可变参数(规则 7),编译器将回退到其他规则和 select 使用最小类型的方法(规则 1)。
您可以使用以下代码确认此行为:
static class SomeClass {
SomeClass(long... value) { System.out.println("Long"); }
SomeClass(int... value) { System.out.println("Int"); }
SomeClass(byte... value) { System.out.println("Byte"); }
}
public static void main(String[] args) throws Exception {
SomeClass o = new SomeClass(); // Byte
}
规则 1 中使用的基元类型之间的精确子类型关系在 JLS 4.10.1. Subtyping among Primitive Types 中进行了解释。
The following rules define the direct supertype relation among the primitive types:
double >1 float
float >1 long
long >1 int
int >1 char
int >1 short
short >1 byte
只有完全没有任何显式构造函数的 classes 获得默认构造函数。对于确实具有一个或多个显式定义的构造函数的 class ,它们的数量(无论是否可变)都没有影响。因此,class 没有 nullary 构造函数是相当普遍的,实际上 class.
就是这种情况
从多个可用的构造函数中进行选择与在重载方法中进行选择的方式相同。首先,确定 available 构造函数。然后,确定那些 适用 给定参数的参数。最后,在适用的构造函数中选择最具体。详细信息在 JLS10 的第 15.12 节中指定。如果该过程未准确识别一个构造函数,则为编译时错误。
在您的示例中,两个可用的构造函数都适用于空参数列表,因此归结为选择最具体的一个问题。 JLS提供了一个非正式的描述:
one method is more specific than another if any invocation handled by
the first method could be passed on to the other one without a
compile-time error.
形式规则围绕形式参数的类型,并说明原始类型之间的形式类型/子类型关系,最终结果是 SomeClass(int...)
比 SomeClass(long...)
更具体适用。那么,前者就是您的示例中选择的那个。
给定这两个构造函数:
SomeClass(int... params)
{
// Do things
}
SomeClass(long... otherParams)
{
// Do other things
}
实例化对象 foo 时会发生什么?
SomeClass foo = new SomeClass();
是否以某种方式调用了未定义的默认构造函数?或者是那些调用了空数组的构造函数之一?如果有,有什么先例?
我做了一些基本测试,发现如果定义了一个没有参数的构造函数,那么它就会被调用。否则,出现调用不明确
根据 this very good answer in "Varargs in method overloading in Java" question below are the rules used by Java compiler for selecting the method signature to invoke. They are based on JLS 5.3. Method Invocation Conversion 文档。
- 基元加宽使用尽可能小的方法参数
- Wrapper 类型不能扩展为另一种 Wrapper 类型
- 您可以将 Box 从 int 变为 Integer 并扩大到
Object
但不能扩大到Long
- 加宽胜过 Boxing,Boxing 胜过 Var-args。
- 你可以先装箱然后加宽(一个
int
可以通过Integer
变成Object
) - 你不能加宽然后加框(一个
int
不能变成Long
) - 您不能将可变参数与加宽或装箱结合使用
因为两个构造函数都是可变参数(规则 7),编译器将回退到其他规则和 select 使用最小类型的方法(规则 1)。
您可以使用以下代码确认此行为:
static class SomeClass {
SomeClass(long... value) { System.out.println("Long"); }
SomeClass(int... value) { System.out.println("Int"); }
SomeClass(byte... value) { System.out.println("Byte"); }
}
public static void main(String[] args) throws Exception {
SomeClass o = new SomeClass(); // Byte
}
规则 1 中使用的基元类型之间的精确子类型关系在 JLS 4.10.1. Subtyping among Primitive Types 中进行了解释。
The following rules define the direct supertype relation among the primitive types:
double >1 float
float >1 long
long >1 int
int >1 char
int >1 short
short >1 byte
只有完全没有任何显式构造函数的 classes 获得默认构造函数。对于确实具有一个或多个显式定义的构造函数的 class ,它们的数量(无论是否可变)都没有影响。因此,class 没有 nullary 构造函数是相当普遍的,实际上 class.
就是这种情况从多个可用的构造函数中进行选择与在重载方法中进行选择的方式相同。首先,确定 available 构造函数。然后,确定那些 适用 给定参数的参数。最后,在适用的构造函数中选择最具体。详细信息在 JLS10 的第 15.12 节中指定。如果该过程未准确识别一个构造函数,则为编译时错误。
在您的示例中,两个可用的构造函数都适用于空参数列表,因此归结为选择最具体的一个问题。 JLS提供了一个非正式的描述:
one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
形式规则围绕形式参数的类型,并说明原始类型之间的形式类型/子类型关系,最终结果是 SomeClass(int...)
比 SomeClass(long...)
更具体适用。那么,前者就是您的示例中选择的那个。