Vararg 方法 Override/Overload 混乱

Vararg methods Override/Overload confusion

计划 1

class B
{
 public void m1(int x)
{
 System.out.println("Super class");
}
}

class A extends B
{
 public void m1(int... x)
{
 System.out.println("Sub class");
}
}

class test1
{
public static void main(String args[])
{
  B b1 = new B();
  b1.m1(10);

  A a = new A();
  a.m1(10);

  B b2 = new A();
  b2.m1(10);
}
}

输出:

  1. 超级class
  2. 超级class(无法理解为什么超级class?!)
  3. 超级class(无法理解为什么超级class?!)

计划 2:

class B
{
 public void m1(int... x)
{
 System.out.println("Super class");
}
}

class A extends B
{
 public void m1(int x)
{
 System.out.println("Sub class");
}
}

class test1
{
public static void main(String args[])
{
  B b1 = new B();
  b1.m1(10);

  A a = new A();
  a.m1(10);

  B b2 = new A();
  b2.m1(10);
}
}

输出:

  1. 超级class
  2. Sub class(无法理解为什么subclass?!)
  3. 超级class(无法理解为什么超级class?!)

大家好,谁能解释一下是否有 overriding/overloading 导致输出?

在您的任何示例中都没有覆盖,因为覆盖需要具有相同名称和签名的方法同时出现在 super-class 和 sub-class 中。您的大多数示例也没有方法重载,因为只有一个版本的 m1 可供编译器选择。

在第一个片段中,编译时类型B 的引用只能看到m1(int x)。编译时类型 A 的引用可以看到这两种方法,但 m1(int x) 仍然是首选,因为它更适合您的方法调用(如果没有匹配传递的参数且不包含可变参数的其他方法)。因此在所有三种情况下都调用了 super-class 方法。

在第二个片段中,编译时类型B的引用只能看到m1(int... x),这就是为什么在第一种和第三种情况下调用该方法的原因。编译时类型A的引用看到两种方法,这次又首选m1(int x),所以第二种情况调用了sub-class方法

问题中根本没有overriding,只有overloading重写 将涉及 A 定义一个具有 相同签名 的方法作为 B 中的相应方法(例如,如果他们都有 m1(int))。在这两个示例中您都没有这样做,因为参数类型不同(intint...)。

JLS §15.12.2: Compile-Time Step 2: Determine Method Signature 涵盖了方法签名解析机制(选择要使用的重载)。 Java 编译器将选择 最具体的方法 它可以在定义的接口上 通过引用的类型 (在你的情况下,变量的类型)如果有任何歧义。

请注意,重要的是引用的类型,而不是引用所引用的对象的类型。引用的类型(在你的例子中是变量)定义了你对对象的接口。 (这是通用 OOP 意义上的 "interface",而不是以它命名的 Java 特定的东西。)编译器只能从该接口中可用的方法中进行选择。

有了这个背景,原因就很清楚了:

计划 1:

  1. 超级class - 因为b1B类型,而B只有m1(int) , m1(10) 匹配它。
  2. 超级class - 因为aA类型; A既有m1(int)(来自B),也有自己的m1(int...);前者 更具体 ,因此使用 Bm1(int)
  3. 超级class - 因为b2B类型,而B只有m1(int)

计划 2:

  1. 超级class - 因为b1B类型,而B只有m1(int...) , 不是 m1(int).
  2. Sub class - 因为 aA 类型,而 A 有两个 m1(int...) (来自 B)以及它自己的 m1(int);后者更具体,因此使用 Am1(int)
  3. 超级class - 因为b2B类型,而B只有m1(int...) , 不是 m1(int).

首先让我解释一下可变参数,这将帮助我更好地回答你的问题。我们使用 vararg 通过省略号(三点符号)提供原始数组作为 method.Denoted 的参数,并且应该始终是该方法的最后一个参数。这就是为什么我们不能在方法中有一个以上的变量参数。在调用方法时,我们可以给出参数的值,也可以忽略。如果方法重载了可变参数和特定类型的参数,那么将验证第一个匹配类型的参数,如果匹配则调用。如果未找到匹配的参数类型,则将验证更高类型(加宽),如果找到则调用。最后它会验证可变参数的参数类型。验证的优先顺序是-

Same parameter type > Higher type > Variable argument

现在开始回答你的问题。

在节目 1 - A 是 B 的 subclass。所以 class A 具有 m1() 方法的实现,其参数类型为 int 和 vararg 类型。 A 的实例正在调用 m1() 方法的 subclass 实现,该方法具有相同的参数类型,因为相同的参数类型比 vararg 具有更高的优先级。

A a = new A();
a.m1(10); // will call higher priority m1() with same parameter type
B b2 = new A();
b2.m1(10); // super class has sub class Obj.Based on dynamic disptch concept, it will always call the method declared in super class

在程序 2 - A 是 B.Only 的子 class 区别在于方法在这里互换了。 Class B 有带 vararg 参数的 m1() 方法,class A 有 int 类型参数。

 A a = new A();
 a.m1(10); // Class A has both m1() method with int and vararg.Will call m1() method with int paramter, as it has higher priority over vararg.

 B b2 = new A();
 b2.m1(10); // Storing sub class reference into super class. Dynamic dyspatch says with super class reference we can call only method declared in super class. Super class has m1() method with vararg, will be called.  

希望这会有所帮助。