Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 面向对象范例中的方法可以被继承类中具有相同签名的方法重写。但是变量可以';T为什么?_Java_Oop_Polymorphism - Fatal编程技术网

Java 面向对象范例中的方法可以被继承类中具有相同签名的方法重写。但是变量可以';T为什么?

Java 面向对象范例中的方法可以被继承类中具有相同签名的方法重写。但是变量可以';T为什么?,java,oop,polymorphism,Java,Oop,Polymorphism,维基百科的定义如下: 在面向对象编程中,虚拟函数或虚拟方法是一种函数或方法,其行为可以在继承类中被具有相同签名的函数重写[以提供多态行为] 根据定义,Java中的每个非静态方法在默认情况下都是虚拟的,除了final和private方法。多态行为无法继承的方法不是虚拟方法 Java中的静态方法永远不能被重写;因此,在Java中将静态方法声明为final是没有意义的,因为静态方法本身的行为与final方法一样。它们可以通过具有相同签名的方法简单地隐藏在子类中。这显然是因为静态方法永远不会有多态行为:

维基百科的定义如下:

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

根据定义,Java中的每个非静态方法在默认情况下都是虚拟的,除了final和private方法。多态行为无法继承的方法不是虚拟方法

Java中的静态方法永远不能被重写;因此,在Java中将静态方法声明为final是没有意义的,因为静态方法本身的行为与final方法一样。它们可以通过具有相同签名的方法简单地隐藏在子类中。这显然是因为静态方法永远不会有多态行为:被重写的方法必须实现多态性,而静态方法则不是这样

从上一段可以得出一个重要结论。C++中的所有方法都默认为静态的,因为C++中没有方法可以在多态性中表现为多态,除非它们在超级类中显式声明为虚拟的。相反,Java中除了final、static和private方法之外的所有方法在默认情况下都是虚拟的,因为它们在默认情况下具有多态行为(在Java中不需要显式地将方法声明为virtual,因此Java没有类似“virtual”的关键字)

现在,让我们从下面的Java简单示例中演示实例变量(也是静态的)不能表现为多态性

class Super
{
    public int a=5;
    public int show()
    {
        System.out.print("Super method called a = ");
        return a;
    }
}


上述代码片段生成的输出如下所示

s、 a=5 c、 a=6 名为a=6的子方法 名为a=6的子方法 在本例中,通过类型为
Super
和类型为
Child
的变量对
show()
方法进行的
s.show()
c.show()
调用分别调用
Child
类中的
show()
方法。这意味着
Child
类中的
show()
方法将覆盖
Super
类中的
show()
方法,因为它们都具有相同的签名

但是,这不能应用于两个类中声明的实例变量
a
。在这种情况下,
s.a
将在
Super
类中引用
a
,并显示
5
c.a
将在
Child
类中引用
a
,显示
6
意味着
Child
类中的
a
(并且不会像非静态方法那样重写)
Super
类中的
a


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

术语“静态”还有另一种用法引用名称解析时:静态解析是指使用声明的变量类型解析名称,动态解析是指使用存储在变量中的数据类型。静态解析可以在编译时完成,而动态解析必须在运行时完成。解析虚拟成员(这是动态解析的一种形式)需要额外的间接层,即表查找。允许“虚拟”字段将导致运行时成本

一旦取消了所有成员的静态解析,使用静态类型的变量就没有什么意义了。在这一点上,您还可以使用动态类型的语言,如Python和大量的Lisp变体。当您放弃静态类型时,尝试谈论不重写的子字段就不再有意义了(或重写)父字段,因为不再有静态变量类型可建议其他类型

class Super(对象):
a=5
def显示(自我):
打印(“名为a=“,end=”)的超级方法)
回归自我
班级儿童(超级):
a=6
def显示(自我):
打印(“名为a=“,end=”)的子方法)
回归自我
#没有迹象表明“s”应该是一个超级。。。
s=儿童();
c=儿童();
#所以s.a是孩子也就不足为奇了
打印(“s.a=”,s.a)
#结果:“s.a=6”
打印(“c.a=”,c.a)
#结果:“c.a=6”
打印(s.show())
#结果:“称为a=6的子方法”
打印(c.show())
#结果:“称为a=6的子方法”
应该注意的是,公共Lisp既有类型声明,也有动态解析

(非通用显示(o))
(defclass super()
((a:accessor super-a)
:表格5
:initarg:a)
)
(方法显示((超级))
(列出“名为a=”的超级方法)
(槽值o'a))
)
(特级儿童(超级)
((a:访问器child-a)
:表格6
:initarg:a)
)
(定义方法显示((o子项))
(列表“名为a=”的子方法”
(槽值o'a))
)
(除雾试验)
(声明(超级s型))
(声明(c类)
(列表(列表“s.a=(插槽值s'a))
(列表“c.a=”(插槽值c'a))
(节目s)
(图c)
)
)
(测试(使实例成为“子对象”)(使实例成为“子对象”)
;result:'(((“s.a=”6)(“c.a=”6)(“称为a=”6的子方法”(“称为a=”6的子方法))
在纯OOP中(根据一些人的说法),对象不应该有公共字段,而应该只有公共成员,所以静态解析字段不是问题

C++中的所有方法(也在C中)默认为静态[…] < /P> <> >不,因为代码>静态< /代码>在爪哇中比“不能重写”更重要,在C++中根本不意味着。静态方法的本质属性是类方法,通过类访问,类

final class Child extends Super
{
    public int a=6;

    @Override
    public int show()
    {
        System.out.print("Child method called a = ");
        return a;
    }
}
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());
    }
}
s.a = 5 c.a = 6 Child method called a = 6 Child method called a = 6