2014-09-13 25 views
0

在下面的例子中,我不明白为什么Base b1 = new Derived(); System.out.println(b1);打印出x=10, z=20。我的理解是,因为b1有一个静态类型的基地,它不能访问Derived中的字段,所以z不应该打印出来。有人可以帮忙解释吗?非常感谢!Java更宽的对象分配转换

class Base { 
    int x; 
    public Base1() { x = 10; } 
    public Base1(int x) { this.x =x; } 
    public String toString() { 
    return "x=" + x ; 
    } 
} 
class Derived1 extends Base1 { 
    int z = x * 2; 
    public Derived1() {} 
    public Derived1(int x, int z) { 
     super(x); 
     this.z = this.z + z; 
    } 
    public String toString() { 
     return "x=" + x + ", z=" + z; 
    } 
    } 
+1

这是多态性的全部目的。 – 2014-09-13 09:20:08

+0

https://en.wikipedia.org/wiki/Method_overriding – khelwood 2014-09-13 09:34:27

回答

2

对象Derived,而不是一个Base。您的接口b1的对象是BaseBasetoString,所以你可以访问toString。您访问的实现是对象所具有的实现,它由Derived提供,它使用zDerived#toString的实现可以访问z,因为其对对象的引用是通过Derived引用(this)引用的,而不是Base引用。

正如Oli在评论中指出的那样,这对多态性具有根本性  —使对象的行为取决于对象而不是对象的接口。

如果对象的内部是由我们所需的接口决定的,那么尝试执行interface s就会遇到一些麻烦! :-)

+0

谢谢!我仍然有点困惑,因为我记得老师说过这样的话:“这个更广泛的任务是可以的,但是b1不能访问Derived中的字段。”那么这是指什么?这是否意味着它可以通过方法访问z,就像你说的,但它不能通过b1.z访问? – user3735871 2014-09-13 09:33:51

+1

@ user3735871:这意味着使用'b1'的代码只能访问'Base'定义的东西,即使对象是一个Derived。这些可能是新方法或新领域。就代码*使用*'b1'而言,'b1'是一个'Base'。但是,当使用'b1'的代码调用由'Base'定义但由Derived实现的对象的方法时,该方法中的代码可以访问Derived定义的所有内容。所以是的,'b1.z'不可访问,但'b1.toString'可以访问'z',因为'b1.toString'由'Derived'实现。 – 2014-09-13 09:38:31

+0

谢谢。现在它变得更有意义!还有一个问题:如果Base中没有toString方法,或者Base中没有toString方法,那么Derived类将无法覆盖它来访问z? – user3735871 2014-09-13 09:50:04

1

直接从http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

子类继承其所有 母公司的公共和保护的成员,无论子类是在什么包,如果子类在同一个包 它的父项,它也继承父项的包私有成员 。您可以使用继承 成员是,取代他们,隐藏起来,或者用新 成员

在你的代码调用默认的构造函数来创建一个新的Derived1对象加以补充:
Base b1 = new Derived();,这反过来又调用父类的默认构造函数,在那里你碰巧设置了x = 10。之后,你去这条线int z = x * 2;