我有两个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);
}
}
答案 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>
图片交叉链接来自另一个网站的图片中的信用,如果这是违反规则,那么有人可以自由编辑我的答案的这一部分。
答案 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 ++中,情况并非如此。调用的方法是变量类型之一(如果存在),除非您通过使方法虚拟显式选择上述行为。