为什么sysout(upper class)在将下层类分配给上层类之后调用下层类的toString?
我有两个类 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();
}
}
正如您在下面的 main 方法中看到的,我将 b 分配给 a。现在“a”无法调用 b 的方法,这一点很清楚,因为我现在使用的是 A 类型的实例。但当调用 toString 时,它的行为类似于 B。好奇的是,我本来期望的是字符串a。为什么会这样呢?
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);
}
}
I have two classes A and B while B is a subtype of 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();
}
}
Class 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();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
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);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
因为a指向B的实现。
并且被声明为A。
因此B的行为。并且A的方法可见。
要使用B方法,请像这样
思考它,
当编译时,仅接受对象方法,即使它是具有很多方法的FancyObjcet。
要在 o 上使用 FancyObject 的方法,请这样做。
引用“因为我现在使用 A 类型的实例”,您仍在使用 B 类型的实例。您可以看到它就像升级了 b 一样,但它是同一个实例。
图片从另一个网站交叉链接,图片中有制作人员,如果这违反规则,那么有人可以自由编辑我答案的这一部分。
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
Think of it like this
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
这是继承/多态性和重写方法的本质。
重写的方法将在运行时根据对象实际类型而不是引用类型确定。
因此a.toString()实际上是b.toString(),因为它是在运行时确定的。
http://download.oracle.com/javase/tutorial/java/IandI /覆盖.html
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
您需要理解的概念是引用和对象之间的区别。
a
是一个引用(在本例中为局部变量),它首先指向A
类型的对象,然后指向B
类型的对象。编译器知道它必须是 A 类型(或其子类型),因此它可以安全地调用 A 定义的所有方法,但它们将在实际对象上调用,而不是在
a
。The concept you need to understand is the difference between References and Objects.
a
is a reference (a local variable in this case) that points first to an Object of typeA
and then to an Object of typeB
.The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of
a
.这就是多态性:a 持有的对象具有静态类型 A,但它仍然是动态类型 B 的对象。因此动态调度选择重写 B 中定义的 toString()。
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
这正是 Java 运行时多态性的工作原理。重要的是运行时的实际类型。您所做的就是获取对
A
的引用并将其指向B
的实例。您已经更改了a
指向的事物的类型。尝试
a = (A)b;
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an
A
and point it at an instance ofB
. You have changed the type of the thing thata
points to.Try
a = (A)b;
不,B 重写了 A 的 toString 方法,因此如果一个对象是 B 的实例,那么当您调用其 toString 方法时,您将获得该实例具有的任何方法。一般来说,如果您有一个对象并调用其方法,则调用的方法是实例中的方法,而不是变量类型中的方法。唯一的例外是静态方法。
在 C++ 中,情况并非如此。所调用的方法是变量类型之一(如果存在),除非您通过将方法设为虚拟来显式选择上述行为。
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
这在 OOP 中称为运行时多态性。
That is called runtime polymorphism in OOP.