Vararg方法覆盖/重载混乱

Aka*_*nya 7 java overriding overloading variadic-functions

计划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);
}
}
Run Code Online (Sandbox Code Playgroud)

输出:

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

计划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);
}
}
Run Code Online (Sandbox Code Playgroud)

输出:

  1. 超级
  2. 子类(无法理解子类的原因?!)
  3. 超类(无法理解为什么超类?!)

各位大家好,有人可以解释是否存在覆盖/超载导致输出?

T.J*_*der 11

这个问题根本没有压倒一切,只是超载.覆盖将涉及A定义具有与相应方法相同的签名的方法B(例如,如果它们都具有m1(int)).在这两个示例中都没有这样做,因为参数类型不同(intvs. int...).

JLS§15.12.2:编译时间步骤2:确定方法签名涵盖了方法签名解析的机制(选择使用哪个重载).如果存在任何歧义,Java编译器将在由引用类型(在您的情况下,变量的类型)定义的接口上选择它可以采用的最具体的方法.

请注意,它是重要的引用类型,而不是引用引用的对象的类型.引用的类型(在您的情况下为变量)定义了对象的接口.(这是通用OOP意义上的"接口",而不是以它命名的Java特定事物.)编译器只能从该接口中可用的方法中进行选择.

在此背景下,原因相当清楚:

计划1:

  1. 超类 - 因为b1是类型B,B只有m1(int),并m1(10)匹配它.
  2. 超级 - 因为a是类型A; A既有m1(int)(来自B)也有自己的m1(int...); 前者是更具体的,所以B的m1(int)被使用.
  3. 超类 - 因为b2是类型B而且B只有m1(int).

计划2:

  1. 超类 - 因为b1是类型B,B只有m1(int...),不是m1(int).
  2. 子类 - 因为a是类型A,并且同时A具有m1(int...)(from B)和它自己的类m1(int); 后者是更具体地,等A的m1(int)使用.
  3. 超类 - 因为b2是类型B,B只有m1(int...),不是m1(int).


Era*_*ran 5

您的任何示例都没有覆盖,因为重写需要具有相同名称和签名的方法才能出现在超类和子类中.大多数示例都没有方法重载,因为只有一个版本m1可供编译器选择.

在第一个片段中,编译时类型的引用B只能看到m1(int x).编译时类型的引用可以A看到这两种方法,但m1(int x)仍然是首选,因为它与您的方法调用更好地匹配(如果没有其他方法与传递的参数相匹配,则只能在方法重载分辨率中选择使用varargs的方法,并且'包含varargs).因此,在所有三种情况下都调用超类方法.

在第二个片段中,编译时类型的引用B只能看到m1(int... x),这就是在第一和第三种情况下调用该方法的原因.编译时类型的引用可以A看到这两种方法,并且这次m1(int x)再次是首选,因此为第二种情况调用子类方法.