Java:重载构造函数之间的选择
Java: selection between overloaded constructors
Per this question,Java 将 select "most specific" 选项当试图在不明确的重载构造函数之间 select 时。在这个例子中:
public class Test{
private Test(Map map){
System.out.println("Map");
}
private Test(Object o){
System.out.println("Object");
}
public static void main(String[] args){
new Test(null);
}
}
它将打印
"Map"
但是,我试图弄清楚 "most specific" 到底是什么意思。我假设它的意思是 "least ambiguous",如 "may refer to the fewest possible types." 在这种情况下,Object
可能是任何不是原始的东西,而 Map
可能只是 Map
或 ? extends Map
。基本上,我假设哪个 class 更接近继承树的叶子将被 selected。当一个 class 是另一个的子 class 时,这有效:
public class Test{
private Test(A a){
System.out.println("A");
}
private Test(B b){
System.out.println("B");
}
public static void main(String[] args){
new Test(null);
}
}
class A{}
class B extends A{}
"B"
然后我想到了这个:
public class Test{
private Test(A a){
System.out.println("A");
}
private Test(E e){
System.out.println("E");
}
public static void main(String[] args){
new Test(null);
}
}
class A{}
class B extends A{}
class C{}
class D extends C{}
class E extends D{}
我认为它应该打印 E
,因为 E
可能只指一种已知类型,而 A
可能指两种(A
和 B
).但它给出了一个模糊的引用错误。
它实际上是如何选择构造函数的?我通读了 the docs 但坦率地说,我不太明白它是如何确定特异性的。我希望能准确描述为什么它不能确定 E
比 A
.
更具体
此行为是因为 E 并不比 A 更具体,因为它们属于不同的层次结构,因此无法进行比较。因此,当您传递空值时,Java 无法知道要使用哪个层次结构。
它不是基于可转换为参数类型的类型的数量 - 由于隐式转换,它是对一个重载有效的任何值是否对另一个重载有效。
例如,存在从 String
到 Object
的隐式转换,但反之则不然,因此 String
比 Object
更具体。
同样存在从 B
到 A
的隐式转换,但反之则不然,因此 B
比 A
更具体。
然而,对于 A
和 E
,两者都不比另一个更具体 - 没有从 A
到 E
的转换,也没有从 [=20] 的转换=] 到 A
。这就是重载解析失败的原因。
JLS 的相关位实际上是 15.12.2.5,其中包括可能使您更容易理解的内容:
The informal intuition is that 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.
所以如果你有:
void foo(String x)
void foo(Object x)
foo(String)
处理的每个调用都可以由 foo(Object)
处理,但反之则不然。 (例如,您可以调用 foo(new Object())
而 foo(String)
无法处理。)
JSL§15.12.2.5 的以下陈述回答了
The informal intuition is that 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.
案例一
- 您可以在采用
Object
的构造函数中传递任何内容,而我们不能在第一个构造函数中传递 Map
以外的任何内容。因此,无论我在 Map
构造函数中传递什么,都可以由 Object
构造函数处理,这就是为什么 Test(Map map)
变得具体。
案例二
- 由于
B
扩展了 A
,这里的 Test(B b)
构造函数变得更加具体。由于 继承 . ,我们可以在 Test(A a)
中传递 B
案例三
- 在这种情况下,没有直接转换来描述更具体的方法,这会导致 歧义。
Per this question,Java 将 select "most specific" 选项当试图在不明确的重载构造函数之间 select 时。在这个例子中:
public class Test{
private Test(Map map){
System.out.println("Map");
}
private Test(Object o){
System.out.println("Object");
}
public static void main(String[] args){
new Test(null);
}
}
它将打印
"Map"
但是,我试图弄清楚 "most specific" 到底是什么意思。我假设它的意思是 "least ambiguous",如 "may refer to the fewest possible types." 在这种情况下,Object
可能是任何不是原始的东西,而 Map
可能只是 Map
或 ? extends Map
。基本上,我假设哪个 class 更接近继承树的叶子将被 selected。当一个 class 是另一个的子 class 时,这有效:
public class Test{
private Test(A a){
System.out.println("A");
}
private Test(B b){
System.out.println("B");
}
public static void main(String[] args){
new Test(null);
}
}
class A{}
class B extends A{}
"B"
然后我想到了这个:
public class Test{
private Test(A a){
System.out.println("A");
}
private Test(E e){
System.out.println("E");
}
public static void main(String[] args){
new Test(null);
}
}
class A{}
class B extends A{}
class C{}
class D extends C{}
class E extends D{}
我认为它应该打印 E
,因为 E
可能只指一种已知类型,而 A
可能指两种(A
和 B
).但它给出了一个模糊的引用错误。
它实际上是如何选择构造函数的?我通读了 the docs 但坦率地说,我不太明白它是如何确定特异性的。我希望能准确描述为什么它不能确定 E
比 A
.
此行为是因为 E 并不比 A 更具体,因为它们属于不同的层次结构,因此无法进行比较。因此,当您传递空值时,Java 无法知道要使用哪个层次结构。
它不是基于可转换为参数类型的类型的数量 - 由于隐式转换,它是对一个重载有效的任何值是否对另一个重载有效。
例如,存在从 String
到 Object
的隐式转换,但反之则不然,因此 String
比 Object
更具体。
同样存在从 B
到 A
的隐式转换,但反之则不然,因此 B
比 A
更具体。
然而,对于 A
和 E
,两者都不比另一个更具体 - 没有从 A
到 E
的转换,也没有从 [=20] 的转换=] 到 A
。这就是重载解析失败的原因。
JLS 的相关位实际上是 15.12.2.5,其中包括可能使您更容易理解的内容:
The informal intuition is that 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.
所以如果你有:
void foo(String x)
void foo(Object x)
foo(String)
处理的每个调用都可以由 foo(Object)
处理,但反之则不然。 (例如,您可以调用 foo(new Object())
而 foo(String)
无法处理。)
JSL§15.12.2.5 的以下陈述回答了
The informal intuition is that 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.
案例一
- 您可以在采用
Object
的构造函数中传递任何内容,而我们不能在第一个构造函数中传递Map
以外的任何内容。因此,无论我在Map
构造函数中传递什么,都可以由Object
构造函数处理,这就是为什么Test(Map map)
变得具体。
案例二
- 由于
B
扩展了A
,这里的Test(B b)
构造函数变得更加具体。由于 继承 . ,我们可以在
Test(A a)
中传递 B
案例三
- 在这种情况下,没有直接转换来描述更具体的方法,这会导致 歧义。