[英]Polymorphism and inheritance
在这种情况下:
class A{
public int x = 4;
public void s3(){
x = 3;
}
public void f(){
x = 8;
s3();
}
}
class B extends A{
public int x = 5;
public void f(){
x = 10;
s3();
}
}
A a = new B();
B b = (B) a;
a.f();
System.out.println(b.x);
System.out.println(a.x);
af()
调用f()
类的B
,然后f()
,分配后,调用s3()
函数。 此时, s3()
仅在A
定义,并且当它向x
赋值3时, x
是类A
拥有的变量的副本。 为什么s3()
不使用B
声明的x
? 从理论上讲, B
不应该拥有从A
继承的s3()
函数的副本吗? (因此从B
A
继承的s3()
应该使用B
声明的x
)
您对继承中的操作有误解。 extends
是一个明智选择的保留字。 B扩展A的要点是说B是具有附加属性的A的子集。 您不应该在B中重新定义x
; A应该处理x
。 通过在子类中重新定义x
,您可以隐藏超类的字段x
(即使x
引用了不同的变量类型,也是如此)。
A a = new B();
System.out.println(a.x); //4 makes sense, since we are of class A
B b = (B) a;
System.out.println(b.x); //5 makes sense, since we are of class B
a.f();
System.out.println(a.x); //3 makes sense, since a.f() calls s3(), which sets A's x to 3
System.out.println(b.x); //10
10之后是打印b的x,通过调用af()
将其分配给10,然后调用s3()
,这就是第三个示例打印3的原因。要了解我的意思,请看以下内容:
public void f()
{
x = 10; //sets B's x to 10
s3(); //calls A's s3(), which sets A's x to 3.
}
因为是一样的。 您没有该对象的两个副本(“实例”),只有一个。
由于您创建的实例是一个B
实例( new B()
),因此将使用B
定义的方法。 当然,如果在B
中未定义任何方法,它将使用超类方法实现。
因此,您只有一个x
属性,而s3
则将其强制为3
。 可以。
为什么s3()不使用B中声明的x?
通常,父类中的方法看不到子类中的成员变量。
我想这样做:
B b = new B();
b.f();
足以再现您至少部分的困惑。 这是f()在B中的样子:
class B extends A{
public int x = 5;
public void f(){
x = 10;
s3();
}
}
f()等效于:
public void f(){
this.x = 10;
this.s3();
}
因此,调用bf()意味着f()等效于:
public void f(){
b.x = 10;
b.s3();
}
接下来,在A的s3()方法内部会发生什么? s3()看起来像这样:
public void s3(){
x = 3;
}
等效于:
public void s3(){
this.x = 3;
}
“ this”是调用该方法的对象,在上一个f()示例中,您可以看到它是b。 因此s3()等效于:
public void s3(){
b.x = 3;
}
所以bx很快就被3 ...覆盖了!
B的实例也继承了A的x,只是B内的x碰巧B的x 遮蔽了A的x。结果,B中的f()方法将B的x赋给了x。内部s3()但是,从a获得的b的x不再被遮蔽了,就A而言,只有一个x-来自A的x。换句话说,对bx的查找取决于该类是什么而不同语句出现在。
执行s3()之后,最终结果是b具有两个带有两个不同值的x。 在B的方法内部,来自B的x将是可见的,而在A的方法内部,来自A的x将是可见的。 在B的内部方法中,可以使用super从A处获得x。
从理论上讲,B不应该拥有从A继承来的s3()函数的副本吗?
不要以副本来思考。 考虑从类到类的指针,以及从类到查找表的指针。 通常在计算机编程中,每个实例都有其自己的实例变量,但是方法由类中的所有实例共享。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.