为什么sysout(上层)在将较低的类分配给上层后调用较低类的toString?

时间:2011-09-07 14:57:27

标签: java oop polymorphism tostring variable-assignment

我有两个A和B类,而B是A的子类型:

public class A {
    private String stringVar;

    public A()  {
        stringVar = "";
    }

    public String getStringVar() {
        return stringVar;
    }

    public void setStringVar(String str) {
        this.stringVar = str;
    }

    @Override 
    public String toString()  {
        return getStringVar();
    }
}

B组:

public class B extends A {
    private int intVar;

    public B()  {
        intVar = 0;
    }

    public int getIntVar() {
        return intVar;
    }

    public void setIntVar(int intVar) {
        this.intVar = intVar;
    }

    @Override
    public String toString()  {
        return super.toString() + " " + getIntVar();
    }
}

正如您在以下主要方法中所看到的,我将b分配给a。现在“a”无法调用b的方法,因为我现在正在使用类型A的实例。但是当调用toString时,它的行为类似于B.好奇,我本来期待的串起来。为什么会这样?

public class Main {

    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        b.setIntVar(200);
        b.setStringVar("foo");
        a = b;
        System.out.println(a);
    }
}

7 个答案:

答案 0 :(得分:2)

因为指向B的实施 并被宣布为A.

B的行为和A的可见方法。

要使用B方法,请执行以下操作

((B) a).getIntVar();

想象这个

Object o = new FancyObject();

编译时,只接受Objects方法,即使它是一个有很多方法的FancyObjcet。

要使用FancyObject的方法,请执行以下操作。

Object o = new FancyObject();
(FancyObject o).fancyMethod();

引用“因为我现在正在使用类型A的实例”你仍在使用类型B的实例。你可以看到它像你已经升级了b但它是同一个实例。< / p>

图片交叉链接来自另一个网站的图片中的信用,如果这是违反规则,那么有人可以自由编辑我的答案的这一部分。 enter image description here

答案 1 :(得分:1)

这是继承/多态和重写方法的本质。

覆盖方法将在运行时基于对象实际类型而不是基于引用类型来确定。

因此a.toString()实际上是b.toString(),因为它是在运行时确定的。

http://download.oracle.com/javase/tutorial/java/IandI/override.html

答案 2 :(得分:1)

您需要了解的概念是引用和对象之间的区别。

a是一个引用(在本例中为局部变量),它首先指向类型为A的对象,然后指向类型为B的对象。

编译器知道它必须是A类型(或其子类型),因此它可以安全地调用A定义的所有方法,但它们将在实际的Object上调用,而不是在{{1}的原始类型上调用}。

答案 3 :(得分:0)

在OOP中称为runtime polymorphism

答案 4 :(得分:0)

这是多态:保持的对象具有静态类型A,但它仍然是动态类型B的对象。因此,动态分派选择在B中定义的重写的toString()。

答案 5 :(得分:0)

这正是Java的运行时多态性的工作原理。重要的是运行时的实际类型。您所做的是引用A并将其指向B实例。您已更改a指向的内容的类型。

尝试

a = (A)b;

答案 6 :(得分:0)

不,B覆盖A的toString方法,因此如果对象是B的实例,当您调用其toString方法时,您将获得该实例具有的任何方法。通常,如果您有一个对象并调用其方法,则调用的方法是实例中的方法,而不是变量类型。唯一的例外是静态方法。

在C ++中,情况并非如此。调用的方法是变量类型之一(如果存在),除非您通过使方法虚拟显式选择上述行为。