为什么Java调用重写的方法,即使对象是上浇铸的?
我有以下课程:为什么Java调用重写的方法,即使对象是上浇铸的?,java,Java,我有以下课程: public abstract class Animal { private String species; public Animal(String ll) { species = ll; } public abstract void speak(); public String toString() { return "Species: " + species; } }
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()方法,甚至在我们将Raven对象“向上投射”到Animal之后?
谢谢。因为这就是多态性的全部含义:您可以在不知道对象的实际具体类型的情况下调用对象的方法,并且将调用在此具体类型中定义的适当方法 这与真实物体的工作原理完全相同:如果我给你一辆车,即使你不知道它实际上是一辆混合动力车,当你驾驶它时,它的行为也会像一辆混合动力车
在您的示例中,
a
和blabla
是对同一对象的两个引用,该对象是Raven
实例。所以这个对象*speak*s和*toString*s就像一只乌鸦。在java中调用一个方法时,即使它被强制转换为超类型,它也总是寻找要调用的最重写的方法
从
隐藏静态方法和重写实例方法之间的区别具有重要意义:
- 被调用的重写实例方法的版本是子类中的版本
- 调用的隐藏静态方法的版本取决于它是从超类还是子类调用的
Java总是使用本文中描述的实例方法: 此处,
a
和blablabla
引用了完全相同的对象,您可以通过以下方式确认:
System.out.println(a == blabla);
// prints "true"
因此,a
实际上是一只乌鸦
,因此它说话自然会像一只乌鸦
,即使你给它贴上了动物的标签
考虑另一种人性化的解释。让实现在子类的对象上执行实际上是非常危险的。想象一个Bicycle
类,以及它更专业的BicycleWithLittleWheels
。关于后者,小轮子非常脆弱,如果你试图骑得太快,它们可能会断裂。若你们让某人骑那个辆自行车,就好像是一辆普通的自行车,很明显是小轮子,他可能会把它弄坏。根据类似的逻辑,你可能不应该像使用大锤一样使用高精度牙钻
这就是为什么,凭直觉,你不应该让一个特殊的对象被视为它更一般的形式。当然,在某些情况下,使用一个专门化的对象可能是有意义的,就好像它是更一般的东西一样,但并不总是如此。编译器如何区分安全案例和不安全案例?那太难了。因此,为了安全起见,语言不会允许您这样做。首先,您将向下
投射对象。其次,这是因为您最初创建了Raven
对象,您创建了对它的引用。blabla
和a
是引用,而不是对象。当您将引用强制转换为对象时,您不会更改对象,并且会调用相同的方法。
System.out.println(a == blabla);
// prints "true"