| sakulagi 回复于:2005-06-17 08:11:15
|
【1】 Field和method不一样,没有overriding,只有hiding。Field是按声明类型(或者叫引用类型),而不是实际类型来解析的。比如你的例子里,如果改成
[code:1:83b2b1ff3e]
Superclass sub = new Superclass();
[/code:1:83b2b1ff3e]
那么sub.x会指向Superclass里的x,即使sub的实际类型是Subclass。
【2】在对Superclass.setX()里边的x作解析的时候,会解析城这样:
[code:1:83b2b1ff3e]
((Superclass)this).x
[/code:1:83b2b1ff3e]
而根据【1】,这个x在任何情况下都被指向了Superclass.x,所以调用setX()永远无法给Subclass.x赋值。
|
| cooljia 回复于:2005-06-17 20:20:25
|
艾, 搞过一段时间sjcp, 所以对此类的题目还是有点印象.
Superclass sub1 = new Subclass();
Superclass super = new Superclass();
sub1.x和super.x在Subclass中的main方法中是指向的都是父类中的x
只有
Subclass sub2 = new Subclass();
sub2.x才是子类中的x.
|
| leonbao 回复于:2005-06-27 18:04:22
|
我认为以上两位并没有完全准确回答楼主的问题。
我认为,原则上父类是看不到子类的方法和属性的,因此在父类里也就不能去调用子类里的方法或改变子类里的属性。
但在子类里可以调用父类的方法或改变父类的属性。不过要分两种情况:
1. 如果在父类里的某一个方法或属性在子类内没有重新定义,那么在子类里可以直接调用父类里的这个方法或者改变这个属性。
class Superclass
{
int x;
void setX()
{
x=10;
}
}
class Subclass extends Superclass
{
void aMethod()
{
x=20; // 改变 SuperClass 里的 x
setX(); // 调用 SuperClass 里的 setX()
}
}
2. 如果在父类里的某一个方法或属性在子类内被重新定义,那么在子类里直接调用或者改变的是在子类里新定义方法或者属性。如想调用父类里被覆盖的方法或改变父类里被覆盖的属性,则必须加super前缀。
class Superclass
{
int x;
void setX()
{
x=10;
}
}
class Subclass extends Superclass
{
int x;
void setX()
{
x=30;
}
void aMethod()
{
x=20; // 改变 SubClass 里的 x
setX(); // 调用 SubClass 里的 setX()
super.x=20; // 改变 SuperClass 里的 x
super.setX(); // 调用 SuperClass 里的 setX()
}
}
在楼主的程序里,SubClass 里的setX() 被注释掉了,因此在运行时是父类的setX()被调用了,而父类的方法只能改变父类里的属性。也就是说父类里的x的值变为10,而子类里的x还是0。main() 里的sub.x 得到的一直是子类里的x的值。
|
| sakulagi 回复于:2005-06-27 22:16:40
|
父类自然是看不见子类的任何内容,因为父类不知道有子类的存在。
但是,对于一个实例来说,它既是父类的实例,也是子类的实例。而一个名字是在运行时解析的,那么这个时候x是指父类里的x,还是子类的x呢?如果把Superclass的setX方法写成
[code:1:a9a7145694]
void setX()
{
this.x=10;
}
[/code:1:a9a7145694]
那么在调用sub.setX()的时候,this.x指的是父类还是子类的实例呢?这个this.x是父类的x还是子类的x?
所以探讨一下名字解析的规则还是有意义的。
另外,如果子类定义了和父类相同签名的方法,那么在父类里调用的将是子类的方法。这个是Java的最基本的特性了。所以不能笼统的说“父类不能访问子类的方法和属性”。方法和属性的访问规则是不一样的。
|
| tangchaodong 回复于:2005-06-28 14:06:29
|
int x; //隐藏了父类的成员变量x
把该句隐掉就得到了0,10
|
| rabbit008 回复于:2005-06-29 10:59:49
|
1. //Test.java
public class Test extends Super2{
int x=2;
void setx(int value){
x = value;
}
int getsuperx(){
return super.x;
}
public static void main(String[] args)
{
try{
Test t = new Test();
System.out.println(t.x);//2
t.setx(10);
System.out.println(t.getX());//0
System.out.println(t.getsuperx());//1
System.out.println(t.x);//10
}catch(Exception e){
e.printStackTrace();
}
}
}
class Super1{
int x=0;
void setx(int value){
x = value;
}
}
class Super2 extends Super1{
int x=1;
void setx(int value){
x = value;
}
int getX(){
return super.x;
}
}
2. //Test.java
public class Test extends Super2{
int x=2;
/*void setx(int value){
x = value;
}*/
int getsuperx(){
return super.x;
}
public static void main(String[] args)
{
try{
Test t = new Test();
System.out.println(t.x);//2
t.setx(10);
System.out.println(t.getX());//0
System.out.println(t.getsuperx());//10
System.out.println(t.x);//2
}catch(Exception e){
e.printStackTrace();
}
}
}
class Super1{
int x=0;
void setx(int value){
x = value;
}
}
class Super2 extends Super1{
int x=1;
void setx(int value){
x = value;
}
int getX(){
return super.x;
}
}
3. //Test.java
public class Test extends Super2{
/* int x=2;
void setx(int value){
x = value;
}*/
int getsuperx(){
return super.x;
}
public static void main(String[] args)
{
try{
Test t = new Test();
System.out.println(t.x);//1
t.setx(10);
System.out.println(t.getX());//0
System.out.println(t.getsuperx());//10
System.out.println(t.x);//10
}catch(Exception e){
e.printStackTrace();
}
}
}
class Super1{
int x=0;
void setx(int value){
x = value;
}
}
class Super2 extends Super1{
int x=1;
void setx(int value){
x = value;
}
int getX(){
return super.x;
}
}
写了程序测试了一下,好像有点明白了:)。
当子类调用一个方法时,它会一层一层的向上找,也就是先再自己的类中找,然后到父类中找,以此类推,直到找到为止,而这个方法要赋值的字段,只会改变本类和祖先类的字段,而不会改变子类的字段。
当子类使用一个字段时,也是同样的原则,它会一层一层的向上找,也就是先再自己的类中找,然后到父类中找,以此类推,直到找到为止。
看看例子了。
第一个例子,子类中有字段x , 和 setx() 方法, 所以调用 的字段,方法都是它本身的,在调用setx() 之前,字段 x 是 2 (而不是 1 或 0), 调用了 setx(10) 后(相当于改变了自己类中的字段x的值),得到的 x 为10 ,super.x 为1, super.super.x 为 0。
第二个例子,子类中有字段x , 但没有 setx() 方法, 所以调用 的字段是它本身的,而方法是其父类的,在调用setx() 之前,字段 x 是 2 (而不是 1 或 0), 调用了 setx(10) 后(由于自己的类中没有setx()方法,向上寻找,在父类中找到了setx(), 但是调用父类的方法只会改变父类的字段或父类的父类的字段,由于父类中有x这个字段,所以父类的字段x被改成了10),得到的 x 为2 ,super.x 为10, super.super.x 为 0。
第三个例子,子类中没有字段x , 也没有 setx() 方法, 所以调用 的字段和方法方法都是其父类的,在调用setx() 之前,字段 x 是 1 (不是 0,说明是父类的字段值), 调用了 setx(10) 后(由于自己的类中没有setx()方法,向上寻找,在父类中找到了setx(), 但是调用父类的方法只会改变父类的字段或父类的父类的字段,由于父类中有x这个字段,所以父类的字段x被改成了10),得到的 x 为10,super.x 为10, super.super.x 为 0。
您可以接着把父类中的 setx() 方法隐掉,保留x,看看会得到什么结果。
x=1, after setx(10), x = 1, super.x=1, super.super.x=10
把 父类中的 x 隐掉, 保留 setx(),
x=0, after setx(10), x = 10, super.x=10, super.super.x=10
|
| tangchaodong 回复于:2005-06-29 13:56:58
|
我也是这样想的,哈哈!
这算不算是java运行的机制?
|
| sakulagi 回复于:2005-06-29 18:49:54
|
这个可以查看Java Language Specification
|