我正在进行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
的实例?
答案 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}}方法,C
是c
的对象。因此,它会调用C
的{{1}}方法。另一方面,变量print1()
未被覆盖。
要调用超类方法,您可以执行以下操作:
C
答案 3 :(得分:0)
这里,在所有类中使用相同的命名实例变量来混淆编译器,但是您应该知道只能覆盖成员函数而不是成员变量。
因此,所有三个x
将分别存储在内存中。但public void print1()
将被其子类覆盖。所以,
((A)c).print1();
这段代码将调用C类中定义的重写方法。无论您在哪个类中投放类C
的对象。但在第二种情况下((A)c).x
将打印类A
中的值。
((A)c).x
: - 这将引用属于类x
的变量A
而不是类C
。因为变量永远不会在继承中被覆盖。答案 4 :(得分:0)
((A)c)中.print1();实际上它类似于c.print1(); 。 使用A类对其进行类型转换并不重要,它仍然会调用C类的print1()函数。