我有以下课程:
public abstract class Animal
{
private String species;
public Animal(String ll)
{
species = ll;
}
public abstract void speak();
public String toString()
{
return "Species: " + species;
}
}
第二课:
public class Raven extends Animal
{
String name;
public Raven(String emri)
{
super("Raven");
name = emri;
}
public void speak()
{
System.out.println("krra krra");
}
public String toString()
{
return super.toString() + "\nName : "+ name ;
}
}
和测试类:
public class TestAnimals
{
public static void main(String args[])
{
Raven blabla = new Raven("Ziosh");
Animal a = blabla;
System.out.println(a.toString());
}
}
当我执行测试课时,我得到:
Species: Raven
Name: Ziosh
我不明白为什么Java会使用" new" toString()方法,即使我们" upcast" Raven对象是动物? 感谢。
答案 0 :(得分:7)
因为那是多态性的全部内容:您可以在不知道对象的实际具体类型的情况下调用对象的方法,并且将调用在此具体类型中定义的适当方法。
这就像真实的物体一样:如果我给你一辆车,即使你不知道它实际上是一辆混合动力汽车,当你驾驶它时,汽车的行为就像一辆混合动力汽车。 / p>
在您的示例中,a
和blabla
是对同一对象的两个引用,它是Raven
实例。所以这个对象*说* s和* toString * s就像Raven。
答案 1 :(得分:3)
当你在java中调用一个方法时,即使它被强制转换为超类型,它总是会查找调用次数最多的方法。
来自http://docs.oracle.com/javase/tutorial/java/IandI/override.html
隐藏静态方法和覆盖实例方法之间的区别具有重要意义:
- 被调用的重写实例方法的版本是子类中的版本。
- 被调用的隐藏静态方法的版本取决于它是从超类还是从子类调用。
答案 2 :(得分:1)
Raven blabla = new Raven("Ziosh"); Animal a = blabla;
此处,a
和blabla
引用完全相同的对象,您可以通过以下方式确认:
System.out.println(a == blabla);
// prints "true"
因此,a
实际上是Raven
,所以即使您将其标记为Raven
,它也会像Animal
一样说话。
从人的角度考虑另一种解释。让实现在子类的对象上执行实际上可能非常危险。想象一下Bicycle
类,它更专业BicycleWithLittleWheels
。关于后者的事情,小轮子是非常脆弱的,如果你试图骑得太快,它们可能会破裂。如果你让某人骑自行车就好像是一辆普通的自行车,完全明显的小轮子,他可能会打破它。按照类似的逻辑,你可能不应该像大锤那样使用高精度牙钻。
这就是为什么,直观地说,你不应该让一个专门的对象被视为更一般的形式。当然,在某些情况下,使用专门的对象可能是有意义的,就好像它是更通用的东西,但并非总是如此。编译器如何将安全案例与不安全案件区分开来?那太难了。因此,为了保持安全,语言不会让你这样做。
答案 3 :(得分:0)
Java总是使用该帖子中描述的实例方法: java override method invocation