Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java调用重写的方法,即使对象是上浇铸的?_Java - Fatal编程技术网

为什么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"