动态方法不匹配概念.它的输出是什么?



我对这个问题(写在下面)感到困惑,我认为它的答案应该是20,但为什么是10。如果我错了,那么有人能给我指引它的流向吗?

class A
{
int i = 10;
}
class B extends A
{
int i = 20;
}
public class MainClass
{    
public static void main(String[] args)
{
A a = new B();
System.out.println(a.i); //Output of this line
}
}

要深入了解表达式是如何求解的,有必要参考" Java®虚拟机规范">,例如Java SE 7版。

5.4.3.2字段分辨率

解析从D到a中的字段的未解析的符号引用类或接口C,由字段给出的对C的符号引用引用必须先…

但是,基本上,每个类型都有自己的分辨率表.

如果知道一个对象的类型是A,那么将使用解析表A。如果已知是B类型,则使用B表。

在示例中:

static class A { int i = 10; }
static class B extends A { int i = 20; }
public static void main(String[] args) {
B b = new B();
A a = b;
A c = new A();
System.out.println("#1 A: " + a.i);
System.out.println("#2 A: " + ((B)a).i); // (correct) downcast!
System.out.println("#3 B: " + b.i);
System.out.println("#4 C: " + ((B)c).i); // (wrong) downcast!
}

与输出

#1 A: 10
#2 A: 20
#3 B: 20
Exception in thread "main" java.lang.ClassCastException: Test$A cannot be cast to Test$B

10或20取决于是否使用这张表或另一张表。

一个重要的问题是知道如何区分何时已知类型被认为是

在编译时和在运行时考虑类型时!输出#1和#3在编译时分别为AB。这就是为什么得到10或20的原因.

让我展示一下编译时和运行时的区别。

在<<p> strong>运行时a变量实际上是一个B对象,你可以运行 检查它
System.out.println(a.getClass());

与输出

Test$B

即,虽然a被定义为类型,但A实际上是B类型的对象。

在编译时,您说这是A a = b,然后,A解析表被写入(要使用)到JVM字节码,这就是为什么你得到10而不是20。

(附加说明)

在内部,对象A将被存储(非常粗略地))像

@ +--------+
| i = 10 |
+--------+

带分辨率表

A::i := @+0    // to get i from the start position plus 0

对象B将包含它们的基类和自身,如

@ +--------+
| i = 10 |
+--------+
| i = 20 |
+--------+

带分辨率表

B::i := @+1    // to get i from the start position plus 1

JVM当被要求访问*::i字段时,根据表AB使用+0+1

为了证明它,你可以运行
B b = new B();
A a = b;
System.out.println("#1: " + a.i++);
System.out.println("#2: " + ((B)a).i++);
System.out.println("#3: " + a.i);
System.out.println("#4: " + ((B)a).i);

与输出

#1: 10
#2: 20
#3: 11
#4: 21

显示10和20有两个不同的变量,即使它们是同一个对象。

new B()返回B类型对象的引用,该对象是A的子类,因此可以将变量或类型A赋值给B类型的引用

现在当我们在变量a上调用方法时我们可以访问哪个方法

  1. 方法只在A类中定义
  2. 特殊情况如果我们在类B中重载了方法那么对该方法的任何调用都会调用该方法的类B版本

尝试阅读继承、重载和多态性

相关内容

  • 没有找到相关文章

最新更新