关于继承,这该如何理解

mqysbb 2004-11-21 10:19:25
class A {
String s;
public A() {
s = "class : A";
}
public void method() {
}
}
class B extends A {
String s;
public B() {
s = "class : B";
}
public void method() {
System.out.println("hello world" + s);
}
}
public class Test {

public static void main(String[] args) {
A b2 = new B();
b2.method();
System.out.println(b2.s);
}
}
输出:
hello worldclass : B
class : A
b2中的变量s输出不同的值,这该如何理解呢?
...全文
238 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
csforgood 2004-11-21
  • 打赏
  • 举报
回复
给你个例子
比如 鸟和动物的关系
第一 鸟就是鸟,它不会因为用不同的表示法来形容就改变它原来的实例,也就是说虽然鸟是动物,但是实际上它是一个鸟类产生出来的对象,而不是一个动物类的对象
第二 当你把鸟当动物来看,你只能使用动物类的属性和方法 也就是说如果鸟有个新的方法 比如鸟会唱歌,可是你把它当动物看时,你根本不知道它是只鸟,怎么会知道它会唱歌呢,所以你把它当动物看时不能使用子类才有的方法
第三 如果父类有方法被子类覆盖时 那么你以父类的身份来调用这个方法时 将会执行子类的方法。举例说 动物类有个“运动”的方法 ,鸟继承并修改了这个方法 改为 “飞” 了 那么当你用动物的观点调用这个方法 那么它实际上 是飞 。所以只要当初它产生时始鸟的实例 它永远都是 所以不管你把它当什么看 它 就是会飞 它都回执行自己的方法
skylovers 2004-11-21
  • 打赏
  • 举报
回复
launch401(Walking in the Air)

是不是可以这么理解:动态绑定只绑定方法,而不绑定属性
----------------------------------------
java中的所有绑定都是后绑定(就是所谓的“动态绑定”)
见TIJ中关于绑定的说明(我的版本不是候老师的那个):

7.2.1 方法调用的绑定
将一个方法调用同一个方法主体连接到一起就称为“绑定”(Binding)。若在程序运行以前执行绑定(由编译器和链接程序,如果有的话),就叫作“早期绑定”。大家以前或许从未听说过这个术语,因为它在任何程序化语言里都是不可能的。C编译器只有一种方法调用,那就是“早期绑定”。
上述程序最令人迷惑不解的地方全与早期绑定有关,因为在只有一个Instrument句柄的前提下,编译器不知道具体该调用哪个方法。
解决的方法就是“后期绑定”,它意味着绑定在运行期间进行,以对象的类型为基础。后期绑定也叫作“动态绑定”或“运行期绑定”。若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。不同的语言对后期绑定的实现方法是有所区别的。但我们至少可以这样认为:它们都要在对象中安插某些特殊类型的信息。
Java中绑定的所有方法都采用后期绑定技术,除非一个方法已被声明成final。这意味着我们通常不必决定是否应进行后期绑定——它是自动发生的。
为什么要把一个方法声明成final呢?正如上一章指出的那样,它能防止其他人覆盖那个方法。但也许更重要的一点是,它可有效地“关闭”动态绑定,或者告诉编译器不需要进行动态绑定。这样一来,编译器就可为final方法调用生成效率更高的代码。

请注意绑定的概念:

将一个**方法**调用同一个**方法主体**连接到一起就称为“绑定”(Binding)。

特指方法。



launch401 2004-11-21
  • 打赏
  • 举报
回复
是不是可以这么理解:动态绑定只绑定方法,而不绑定属性
skylovers 2004-11-21
  • 打赏
  • 举报
回复
顺便一提,你B中所有方法中调用的s都等于this.s,也就是B.s,而在外部调用s就是“对象.s”了。你的对象是A,当然s就是A.s啦
skylovers 2004-11-21
  • 打赏
  • 举报
回复
你的构造函数实际等于:

public B() {
this.s = "class : B";
}

楼主如果把B改成:
public B() {
super.s = "class : B";
}
也许你就可以看到差别了。
skylovers 2004-11-21
  • 打赏
  • 举报
回复
老兄你跟一下。

我在B中再添加方法:
public String getS() {
return s;
}


A b2 = new B();
其实是生成了一个子类B的对象,其中含有
String s(A)="class : A";
String s(B)="class : B";(其实这里,B的S如果你改成K或者其他名字会更好理解,他是B的一个“私有”变量,与A无关)

和B.method(),B.getS()
而B.method()复写了A.method();


可是你把他强制转换成了B的super类。于是b2的s还是A的s,s(B)已经被屏蔽。method已经被复写,而A由于没有getS()方法,所以你无法访问该方法。

如此解释楼主不知道明白了否...
catblue 2004-11-21
  • 打赏
  • 举报
回复
我觉的这是一个多态的问题。

方法调用的是 new 出来的那个对象。
而参数则相反
chanceqw 2004-11-21
  • 打赏
  • 举报
回复
b2的类型是实际赋给的类型,虽然其使用看起来是声明的类型
b2 instanceof B 结果是 true
b2 instanceof A 结果也是 true
jxj12345678 2004-11-21
  • 打赏
  • 举报
回复
啊啊啊.不错.让我懂了不少.
感谢楼主提出问题,感谢所有解答问题的人.
yxs001 2004-11-21
  • 打赏
  • 举报
回复
与动态绑定有关
ECNU_SEI_kingsang 2004-11-21
  • 打赏
  • 举报
回复
恩,多谢楼上两位大虾指点。又让我长了见识。反正写东西的时候尽量避免这种情况的出现。
launch401 2004-11-21
  • 打赏
  • 举报
回复
Java中动态创建类的类Proxy,也是只支持method而不支持field,也许是因为jvm技术的问题,或者设计者为了强迫用户封装吧,因为oo不鼓励直接调field
skylovers 2004-11-21
  • 打赏
  • 举报
回复
这个...至于为什么,也许是处于命名空间的考虑吧,当一个类的根系非常的深,谁敢保证自己命名的属性不会和上面的正好重合?那么对属性的修改就必须非常小心翼翼了。

而方法则会通过你所指定的类去复写,不存在这个问题。

个人浅薄理解....我再想想...
ECNU_SEI_kingsang 2004-11-21
  • 打赏
  • 举报
回复
楼上可能没有理解我的意思,如果你用super.s的话,就是唯一确定了类型。我的意思是这样的:

class BaseClass {
public String s;
public BaseClass () {
this.s = "baseclass";
}
}

class _A extends BaseClass{
public String s;
public _A () {
this.s = "_A class";
}
}

class _B extends BaseClass{
public String s;
public _B () {
this.s = "_B class";
}
}

class _C extends BaseClass{
public String s;
public _C () {
this.s = "_C class";
}
}

class _D extends BaseClass{
public String s;
public _D () {
this.s = "_D class";
}
}

public class FieldInstanceTest {
public static void main (String[] args) {
BaseClass[] b = new BaseClass[4];
b[0] = new _A();
b[1] = new _B();
b[2] = new _C();
b[3] = new _D();
for (int i = 0; i < b.length; i++)
System.out.println(b[i].s);//我希望打印出_A class
// _B class
// _C class
// _D class,然而我看到属性并不支持动态
//帮定,我现在懂了。我的问题是JAVA的设计者为什么不让属性动态帮定,对于这个例子,我只能
//通过 创建类似_A a = new _A()的对象,然后a.s,b.s,c.s,d.s来实现我想要的结果,这样不是很麻烦吗?
}
}
skylovers 2004-11-21
  • 打赏
  • 举报
回复
你可以指定super.s来用父类的属性啊。
ECNU_SEI_kingsang 2004-11-21
  • 打赏
  • 举报
回复
to 楼上:多谢解答。我基本搞懂了,实际上就一句话,属性不支持动态帮定。就是说即使属性的名称和super class的属性名称一样,也不能实现象多态那样的机制。这就是我郁闷的地方,为什么JAVA程序设计语言为什么不支持属性的动态帮定。
triLine 2004-11-21
  • 打赏
  • 举报
回复
数据成员是在编译时确定的,而方法是在运行时确定的.

skylovers 2004-11-21
  • 打赏
  • 举报
回复
ECNU_SEI_kingsang(myjava) ( ) 信誉:100

这个我已经回答过了.
----------------------------------------
请注意绑定的概念:

将一个**方法**调用同一个**方法主体**连接到一起就称为“绑定”(Binding)。

特指--方法,而不是“属性”。
----------------------------------------
请发问前先看别人的回复。

对于B.s来说,与A.s没有任何关系,一个是this.s,一个是super.s。所以B的String 这个东西是叫s或者k无关紧要。

b2构造以后,含
super.s
this.s
super.method()=this.method()
而,你把b2强制转换成A,则this.s将被屏蔽。属性是不能够被复写的。即使名字一样。把楼主的代码改一下:
class A {
String s;
public A() {
s = "class : A";
}
public void method() {
}
}
class B extends A {
String k;
public B() {
this.k = "class : B";
}
public void method() {
System.out.println("hello world" + k);
}
}
public class Test {

public static void main(String[] args) {
A b2 = new B();
b2.method();//调用的实际上是A.method();但是此method已经被B给复写。
System.out.println(b2.s);//这里你不能访问b2.k,因为b2是A,没有k.(即使实际上b2含有,但是无法通过A的方法访问。)
}
}

和上面的效果是一样的,不知道看明白没有。
ECNU_SEI_kingsang 2004-11-21
  • 打赏
  • 举报
回复
本人也是JAVA初学者,对于这个问题我也感到非常疑惑.JAVA不是号称能动态绑定吗??但是对于类字段属性为什么没有这么做???
下面是我的理解,从这个简单程序分析,首先编译器装载A b2 = new B();即调用B的构造函数,而B是extends A的,所以先调用A的构造函数,然后再调用B的构造函数,至此,构造完毕。现在看b2.method(),这句没有问题,能执行动态帮定.但是b2.s这句我就看不懂了,按照动态帮定的话,应该会调用B.s,但它为什么会调用A.s呢??楼上有位朋友的意思是包的可见性问题.而且建议换个实例变量,那这样的话,怎么测试动态帮定啊??动态帮定就是需要名称和型别都一样才能产生多态的效果.所以我觉得属性是不是没有动态帮定呢????请懂JAVA的朋友给我一个明确的答复
skylovers 2004-11-21
  • 打赏
  • 举报
回复
恩,自类对父类的方法复写是覆盖型的。

当然,用楼主的方法,我们仍然可以调用b.s,a.s,无非就是重载几个方法,用super和this去区分而已.

62,610

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧