2

抱歉,如果以前出现过这种情况,但我没有看到有关此的其他线程。但是如果有的话,请给我链接。

这里我有一个简单的程序。当它运行时,它会打印出“6 4”

public static void main(String[] args) {
    Foo foo = new Foo();
    foo.t = 6;
    foo.f = 4;

    Bar b = new Foo();

    ArrayList<Bar> list = new ArrayList<Bar>();
    list.add((Bar) foo);

    Foo foo2 = (Foo) list.get(0);

    System.out.println(foo2.t + " " + foo2.f);
}

static class Bar {
    int t;
}

static class Foo extends Bar {
    int f;
}

这看起来很奇怪,因为我认为当我将 Foo 添加到列表时,它会删除 f 字段,因为列表包含没有 f 的 Bars。

但似乎 f 在被投射到 Bar 后仍然存在。有人可以解释这是为什么吗?

4

5 回答 5

6

即使您施放和取消施放它 n 次,实际对象也将保持不变。
铸造从不添加/删除/更改对象属性。

Bar b = new Foo();

这里 reference 是 type Bar,实际 object 是 type Foo。作为Foo扩展Bar,这意味着它也具有属性ft(Inherited from Bar)。

list.add((Bar) foo);  

在这里,您将其转换为 Bar (Upasting),但实际对象未更改。

(Foo) list.get(0);

在这里,您将其转换回Foo静止的对象类型Foo,其原始值为tf

于 2013-02-07T06:21:29.903 回答
2

这不是多态性的工作方式。它不会从特定对象中删除任何内容。你可以这样想:

  • 内存中有实物
  • 您可以对该对象有不同的引用:Foo、Bar、Object 等。
  • 真实对象不关心引用 - 如果您创建新引用,它不会修改
  • 但是每个引用都决定了您可以通过此引用访问对象的方式。

Foo 的每个实例都可以视为 Bar 的实例。但是在显式转换之后,您可以再次将此实例作为 Foo 操作。如果它最初是 Bar,那么这个转换将在运行时失败。

于 2013-02-07T06:29:04.103 回答
1

在 Java 中,字段不是多态的。

这就是为什么你对此感到困惑。

因此,即使您添加Foo到列表中,它f也将作为它的实际对象存在Foo

以下摘自 Code Ranch - 由 Jim Yingst

这是Java的设计还是限制或我的误解?

这是设计使然。字段的动态解析会使事情运行得更慢,而且真的没有理由需要它,因为您可以将字段设为私有并使用动态解析的方法访问它们。所以字段是在编译时解析的。

于 2013-02-07T06:21:51.870 回答
0

对先前答案的重要补充:将对象添加到列表不会以任何方式更改该对象。因此,如果对象中有一个属性,它会保持不变。

其余的混淆是一个称为多态的特性。由于 Foo 是 Bar,您始终可以将其视为 Bar,但由于 Foo 是经过修改(扩展)的 Bar,它的行为可能与标准 Bar 对象不同。

我希望它有所帮助。

于 2013-02-07T06:28:00.307 回答
0

就像当您将类型转换为超类变量时,您只是无法访问对象的子类属性,但对象保持不变。只是暴露get() and set() methods, 的包装被改变了。您将看不到子类getter-setter方法 API。但是当您将类型转换回子类(基本上展开)时,子类 getter setter 方法对您再次可见。

对象始终保持不变。

于 2013-02-07T06:28:10.677 回答