理解java中的方法重载和重写
我知道方法重载意味着在子类中定义一个与父类同名但参数不同的方法,方法重写意味着在子类中定义一个与父类具有相同签名的方法 然而,我觉得我失去了一些理解。我试过一些例子。我定义了两个类理解java中的方法重载和重写,java,Java,我知道方法重载意味着在子类中定义一个与父类同名但参数不同的方法,方法重写意味着在子类中定义一个与父类具有相同签名的方法 然而,我觉得我失去了一些理解。我试过一些例子。我定义了两个类A和B扩展了A。然后我准备了许多示例,其中包含两种方法的不同组合(方法(A)和方法(B))。例如: 例1:A包含方法(A)和方法(B)和B都不包含 例2:A包含方法(A)和B包含方法(B) 等等。可以有16种这样的组合 现在我创建了类B的两个实例,并在第一个实例中调用了各种方法。我也可以创建实例类型、引用类型和方法
A
和B扩展了A
。然后我准备了许多示例,其中包含两种方法的不同组合(方法(A)
和方法(B)
)。例如:
- 例1:
包含A
和方法(A)
和方法(B)
都不包含B
- 例2:
包含A
和方法(A)
包含B
方法(B)
B
的两个实例,并在第一个实例中调用了各种方法。我也可以创建实例类型、引用类型和方法调用的各种组合,但这将是准备示例的大量组合
怀疑是我正在努力猜测一些示例的输出结果。或者更具体地说,我没有理解,或者我应该说一组最小的规则,可以规定所有示例中的输出。这种混淆是由于引用类型与它所引用的实例类型不同。所以我没有得到哪个方法获得优先权,一个在引用类型中,一个在实例类型中。在下面的示例中,我没有得到示例3、4和5的输出。这是16种可能的组合中的5种。我相信可能还有一些更令人困惑的组合
下面是一些例子
示例1–向下广播产生编译时错误
class A {
public void method(B b)
{
System.out.println("A's method(B)");
}
}
class B extends A {
public void method(B b)
{
System.out.println("B's method(B)");
}
}
A a = new B();
B b = new B();
a.method(b); //outputs B's method(B)
a.method(a); //compile time error: The method method(B) in the type A
//is not applicable for the arguments (A)
示例2–如果需要,可以进行向上投射
class A {
public void method(A a)
{
System.out.println("A's method(A)");
}
}
class B extends A {
public void method(A a)
{
System.out.println("B's method(A)");
}
}
A a = new B();
B b = new B();
a.method(b);
a.method(a);
输出
B's method(A) //upcasting happening
B's method(A)
A's method(B)
B's method(A)
B's method(A)
B's method(A)
示例3
class A {
public void method(A a)
{
System.out.println("A's method(A)");
}
public void method(B b)
{
System.out.println("A's method(B)");
}
}
class B extends A {
public void method(A a)
{
System.out.println("B's method(A)");
}
}
A a = new B();
B b = new B();
a.method(b);
a.method(a);
输出
B's method(A) //upcasting happening
B's method(A)
A's method(B)
B's method(A)
B's method(A)
B's method(A)
示例4
class A {
public void method(A a)
{
System.out.println("A's method(A)");
}
public void method(B b)
{
System.out.println("A's method(B)");
}
}
class B extends A {
public void method(A a)
{
System.out.println("B's method(A)");
}
public void method(B b)
{
System.out.println("B's method(B)");
}
}
A a = new B();
B b = new B();
a.method(b);
a.method(a);
输出
B's method(B)
B's method(A)
示例5
class A {
public void method(A a)
{
System.out.println("A's method(A)");
}
}
class B extends A {
public void method(A a)
{
System.out.println("B's method(A)");
}
public void method(B b)
{
System.out.println("B's method(B)");
}
}
A a = new B();
B b = new B();
a.method(b);
a.method(a);
输出
B's method(A) //upcasting happening
B's method(A)
A's method(B)
B's method(A)
B's method(A)
B's method(A)
当重载时,Java总是尝试选择最具体的方法。 因此,它首先尝试从变量类型(
A
或B
)解析该方法,然后在实例上调用该方法。这就是为什么在第三个示例中它调用方法B.method(A)
您可以看到区别,该方法是通过声明的变量类型来解析的,但是该方法是在变量的实例上调用的。因此,即使变量a
实际上是B
的实例,它仍然通过类a
的静态已知方法解析该方法
在您的第五个也是最后一个示例中,这一点更加清楚。您的类A
只定义了一个方法,该方法将A
的任何实例作为参数。它不在乎任何子类是否有一个具有更具体参数的方法,例如method(B)
它仍然调用method(a)
,因为这是a
类型的变量a
的唯一已知方法
我知道方法重载意味着在子类中定义一个与父类同名但参数不同的方法
不对。如果在同一个类中有另一个具有相同名称但不同签名的方法,则会重载该方法
或者更具体地说,我没有理解,或者我应该说一组最小的规则,可以规定所有示例中的输出
Java语言规范的一节描述了编译器和运行时在确定调用哪个方法时应用的规则。与此问题最相关的小节为15.12.1、15.12.2和15.12.4。这个答案本质上是对那里所说的话的简化
编译器和运行时基本上需要决定三件事:
A
例3
A
中声明了方法的两个重载<代码>方法(A)
在B
a.方法(b)代码>
和方法(A)
在这里都适用,但是方法(B)
更具体,因此在步骤2中选择了方法(B)
方法(B)
在方法(B)
中不被覆盖,因此在步骤3中选择B
中的实现A
a.方法(a)代码> 只有
适用,因此在步骤2选择方法(A)
,因为编译器不知道方法(A)
的运行时类型。请注意,步骤2是在编译时执行的A
在方法(A)
中被覆盖,因此在步骤3中选择B
中的实现B
方法(B)
在B
中也被覆盖,因此a.方法(B)
调用B
中的实现
例5
在A
中只声明了方法的一个重载<代码>B
声明2个重载。其中一个覆盖了A
中的方法(A)
与其他示例不同,在解析a.method时