2013-10-24 53 views
2

假设我有一个名为Fish的超类和一个名为Tuna的子类。我不明白为什么这个工程:困惑于遍历具有多态性的类层次结构

Fish f; 
Tuna t = new Tuna(); 

f=t; // I am confused about this statement 
f.swim(); // (Tuna's swim method is invoked) 

为什么鱼变量允许“参与有”(美好短语想要的)更专业的金枪鱼对象?我明显错误的“noob OOP Java大脑”的工作方式是:

金枪鱼“是一个”鱼是好的。鱼“是”金枪鱼不行。因此f = t不应该是正确的,并且t = f应该是正确的。但从我上面的例子来看,情况正好相反!

非常感谢您的帮助。由于我刚刚开始学习Java,因此我提前为我的无知道歉。

编辑。以下所有答复非常感谢。从他们那里,我现在明白了:

称为f的变量是Fish类型,因此可以包含位于变量t中的数据值(对象引用),因为t指的是Tuna对象,因此是f使用的兼容类型。它是兼容的,因为金枪鱼是鱼。

回答

1

f变量的值是一个参考。这可以是空引用,也可以是对“是鱼”的任何对象的引用。作为Tuna对象是Fish对象,可以复制t的值,该值必须是空引用或对对象Tuna的引用。

作业只是将右侧的表达式的值复制到左侧的变量中。就是这样。

换句话说:任何你可以对Fish做的事情,你可以做到Tuna。所以没有价值t这样的:

f = t; 
f.swim(); 

是荒谬的。 (t可能是理所当然的空引用,但是这并不视为类型系统为这样的问题。)将有始终是一个合适的swim方法来调用,只要t是非空。

将其与另一种类型进行比较。如果我们有:

String s = "foo"; 
f = s; 
f.swim(); 

然后是没有意义的,因为你不能要求一个String游泳。

类型安全规则确保您永远不会尝试调用方法(或访问字段),并发现您使用的方法/字段根本不存在。 Tuna延伸Fish的事实意味着任何你可以用“普通”鱼做的事情,你也可以用金枪鱼做。

+1

字符串不能游泳吗?我的天啊!我开悟了! –

+0

谢谢!我编辑了我的O.P.以反映我所学到的内容。 – user2911290

2

您近了,但您在一个声明中错了。

金枪鱼 “是” 鱼是OK

我同意 - 这意味着声明F = T(鱼=金枪鱼)是正确的。

鱼 “是一个” 金枪鱼也不行

我同意 - 这意味着声明T = F(鲔鱼=)是不正确的。

。因此,f = t不应该好,并且t = f应该是OK

我不同意,由于上面的状态表示你刚才说的相反。 在最后一句中,你说每条鱼都是金枪鱼(t = f),而不是每条金枪鱼都是鱼(f = t) - 这显然是错误的。

如果金枪鱼是鱼,比F = T因为任何金枪鱼都是鱼。但是我们不能说每一条鱼都是金枪鱼吗?

您必须记住=并不意味着相等(在==中有这样的做法),为了更好地理解,请尝试从右向左读取这些语句。

+1

+1表示从右向左阅读。 –

+1

谢谢,我同意,从右向左阅读“作业复制行动”有助于澄清情况。 – user2911290

1

你有鱼超级有游泳的方法,金枪鱼是鱼的子类。 所以 金枪鱼是一种鱼:它的好 但鱼是金枪鱼:不好。 相同 您可以将金枪鱼参考分配给鱼参考,但鱼参考不能金枪鱼。 所以

public class Fish { 
    public void swim(){ 
     System.out.print("Hello Fish"); 
    } 
} 

public class Tuna extends Fish{ 
    public void swim(){ 
     System.out.print("Hello Tuna"); 
    } 


    public static void main(String[] ar){ 
     //Case A 
     Fish f=new Fish(); 
     Tuna t; 
     t=(Tuna) f;//wrong - it will not cast to tuna object 
     t.swim(); 
     //Case B //correct 
     Fish f; 
     Tuna t=new Tuna(); 
     t=f 
     t.swim(); 

    } 
} 
+0

不幸的是,“案例B,正确”的代码不起作用。 – user2911290