Java继承:继承超类成员和变量时的差异

时间:2016-04-13 11:56:41

标签: java inheritance

我正在进行Java继承,我尝试了以下代码

function MyCtrl($scope) {
    $scope.onBlur = function(){  
    if(user.name=="")
        $scope.hasFocus = false;
    }
}

输出

  

从C打印      3
     1

现在,我的问题是,我可以从class A { public int x = 1; public void print1() { System.out.println("Print from A"); } } class B extends A { public int x = 2; public void print1() { System.out.println("Print from B"); } } class C extends B { public int x = 3; public void print1() { System.out.println("Print from C"); } public static void main(String aa[]) { C c = new C(); ((A) c).print1(); System.out.println(c.x); System.out.println(((A) c).x); } } 访问class A member x,但为什么我无法访问class C instance c。我知道,如果我想,我可以致电class A method print1()。但是,我想直接从C类实例访问它。那么通过重写方法,底层子类中丢失了顶级父类方法吗?但是,保留父类成员(尽管隐藏)。为什么这样?有没有办法从类new A().print1();中的类A调用方法而不创建C的实例?

5 个答案:

答案 0 :(得分:1)

修改

这里发生了什么?

当您说((A)c).print1();时,JVM知道实际需要调用的实例print1()的类型为C,因此类C的{​​{1}} 1}}版本已执行。

但是当你输入print1()时,你指的是状态,而不是行为,而且使用((A)c).x类型的引用。将选择哪个版本的A,在编译时决定什么是类型引用(在本例中为x)。这就是为什么你看到A的状态。

来自Java doc的声明也可能对你有用:

  

在一个类中,一个与该字段中的字段同名的字段   超类隐藏超类的字段,即使它们的类型是   不同。在子类中,超类中的字段不能   由简单名称引用。相反,必须访问该字段   通过超级,这将在下一节中介绍。通常   说来,我们不建议隐藏字段,因为它会使代码变得困难   阅读。

为什么会这样?

回答你的问题:

问题1:

  

我的问题是我能够从C类访问A类成员x   实例c

关于变量A,因为它被声明为x,因此不能对其应用任何业务验证。此外,将其声明为public的开发人员意识到封装的概念现在不能应用(显然不推荐)。因此,允许使用子实例访问父状态是没有害处的。因此,使用public,您可以从课程((A)c).x访问x

问题2:

  

但是,保留父类成员(尽管隐藏)。为什么   所以?

这是因为Java不允许您任意使用A来访问继承层次结构中任何父级的行为。其背后的原因是保持封装。您只能使用super.super.super..关键字访问直接父类的行为,但不能超过该关键字。

为了解释它,让我们说你已经实现了类super,如:

B

现在,如果允许class B extends A { public int x = 2; public void print1() { if(x >= 2) { System.out.println("Print from B"); } } } ,您可以轻松绕过类super.super的{​​{1}}方法中的验证,并可以从实例中调用print1()的print1()方法班B

问题3:

  

但是,保留父类成员(尽管隐藏)。为什么   所以?

如前所述,保留封装。

问题4:

  

有没有办法在C类中调用A类中的方法而没有   创建A?

的实例

因此,无法使用A的实例从C访问print1()

答案 1 :(得分:0)

当你覆盖已经在base(parent)类中实现的函数时,当你在子类中调用该函数时,当你调用print1()时,子类中的类会自动调用C对象:

C c = new C();
c.print1();

您将调用覆盖功能。但是,如果在您的程序的任何部分,您认为您需要为任何案例调用顶级父类(super无法完成),那么您应该重新考虑您的设计策略;也许你不应该覆盖print1(),或者你不应该首先将print1()放在基类中

答案 2 :(得分:0)

在面向对象编程中,只有方法才能被覆盖。您无法覆盖数据成员。这就解释了为什么你得到输出。

print1()中覆盖A的{​​{1}}方法,Cc的对象。因此,它会调用C的{​​{1}}方法。另一方面,变量print1()未被覆盖。

要调用超类方法,您可以执行以下操作:

C

答案 3 :(得分:0)

这里,在所有类中使用相同的命名实例变量来混淆编译器,但是您应该知道只能覆盖成员函数而不是成员变量。

因此,所有三个x将分别存储在内存中。但public void print1()将被其子类覆盖。所以,

  1. ((A)c).print1();这段代码将调用C类中定义的重写方法。无论您在哪个类中投放类C的对象。
  2. 但在第二种情况下((A)c).x将打印类A中的值。

    1. ((A)c).x: - 这将引用属于类x的变量A而不是类C。因为变量永远不会在继承中被覆盖。

答案 4 :(得分:0)

((A)c)中.print1();实际上它类似于c.print1(); 。 使用A类对其进行类型转换并不重要,它仍然会调用C类的print1()函数。