面向对象范例中的方法可以被继承类中具有相同签名的方法覆盖.然而,变量不能.为什么?

Lio*_*ion 5 java oop polymorphism

维基百科将虚拟方法定义为:

在面向对象的编程中,虚函数或虚方法是一种函数或方法,其行为可以通过具有相同签名的函数在继承类中被覆盖[以提供多态行为].

根据定义,除了 final方法和私有方法之外,Java中的每个非静态方法都是默认的虚拟方法.不能为多态行为继承的方法不是虚方法.

Java中的静态方法永远不能被覆盖; 因此,在Java中将静态方法声明为final是没有意义的,因为静态方法本身就像最终方法一样.它们可以通过具有相同签名的方法隐藏在子类中.显然是这样,因为静态方法永远不会有多态行为:被覆盖的方法必须实现多态,而静态方法则不然.

从前一段开始,可以推动一个重要的结论.默认情况下,C++中的所有方法都是静态的,因为除非在超类中显式声明为虚拟,否则C++中的任何方法都不能以多态方式运行.相比之下,除了final,static和private方法之外,Java中的所有方法都默认是虚拟的,因为它们默认具有多态行为(不需要在Java中将方法显式声明为虚拟,因此,Java没有像"virtual"这样的关键字).

现在,让我们演示实例变量(静态)也不能通过Java中的以下简单示例进行多态操作.

class Super
{
    public int a=5;
    public int show()
    {
        System.out.print("Super method called a = ");
        return a;
    }
}
Run Code Online (Sandbox Code Playgroud)
final class Child extends Super
{
    public int a=6;

    @Override
    public int show()
    {
        System.out.print("Child method called a = ");
        return a;
    }
}
Run Code Online (Sandbox Code Playgroud)
final public class Main
{
    public static void main(String...args)
    {
        Super s = new Child();
        Child c = new Child();

        System.out.println("s.a = "+s.a);
        System.out.println("c.a = "+c.a);        

        System.out.println(s.show());
        System.out.println(c.show());
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码片段产生的输出如下.

s.a = 5
c.a = 6
Child method called a = 6
Child method called a = 6

在这个例子中,两个呼叫s.show()c.show()到由show()通过型的变量方法Super和类型的Child,分别调用show()的方法中Child类.这意味着,show()在该方法中Child类覆盖了show()在该方法Super的类,因为它们两者具有相同的签名.

但是,这不能应用于a在两个类中声明的实例变量.在这种情况下,s.a要提到aSuper类和显示5c.a将提及aChild类和显示6意味着aChild类只是隐藏(以及如发生在非静态方法不覆盖)aSuper类.

经过长时间的讨论,只有一个问题.为什么实例变量(以及其余变量)没有被覆盖?实施这种机制的特殊原因是什么?如果它们被覆盖了,会有任何优点或缺点吗?

Ale*_*exR 3

我认为重写的目的是在不改变签名的情况下改变功能。这仅与方法相关:方法可能具有相同的签名但具有不同的行为。字段只有“签名”,也仅限于类型和名称。它们没有行为,所以没有什么可以被覆盖。

无法“覆盖”字段的其他原因是字段通常是私有的(或应该是私有的),因此它们实际上是类实现的血淋淋的细节。然而,方法代表类的外部接口。该外部接口应该支持多态,以便更容易地更改模块的功能而不更改模块之间的关系。