Java对象的表现很奇怪

时间:2013-02-07 06:18:45

标签: java object casting subclass superclass

很抱歉,如果之前已经出现过,但我没有看到另一个关于此问题的帖子。但如果有,请给我链接。

这里有一个简单的程序。当它运行时,它打印出“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的条形码。

但似乎f在被投入酒吧后仍然存在。有人可以解释为什么会这样吗?

5 个答案:

答案 0 :(得分:6)

即使你施放和取消它多次,实际物体也会保持不变 投射从不添加/删除/更改对象属性。

Bar b = new Foo();

此处引用的类型为Bar,实际对象的类型为Foo。由于Foo扩展了Bar,这意味着它还具有属性ft(继承自Bar)。

list.add((Bar) foo);  

在这里你将它投射到Bar(Upasting)但实际对象没有改变。

(Foo) list.get(0);

此处您将其强制转换回Foo仍为Foo的对象,其tf的原始值。

答案 1 :(得分:2)

多态性的工作原理并非如此。它不会从特定的对象中删除任何内容。 你可以这样思考:

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

Foo的每个实例都可以被视为Bar的实例。 但是在显式强制转换之后,您可以再次使用此实例作为Foo。 如果它最初是Bar,则此转换将在运行时失败。

答案 2 :(得分:1)

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

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

因此,即使您将Foo添加到列表中,f也将与Foo一起作为{{1}}的对象。

<强> Following is taken from Code Ranch - by Jim Yingst

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

这是设计的。动态分辨字段会使事情运行得慢一些,并且实际上没有理由需要它,因为您可以将字段设为私有并使用方法访问它们,这些方法是动态解析的。因此,字段在编译时被解析。

答案 3 :(得分:0)

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

其余的混淆是一种叫做多态的特征。由于Foo是Bar,因此您可以将其视为Bar,但由于Foo是经过修改(扩展)的Bar,因此它可能与标准Bar对象的行为不同。

我希望它有所帮助。

答案 4 :(得分:0)

就像你在Super Class变量中输入强制类型一样,你只是无法访问对象的子类属性,但是对象保持不变。只是暴露get() and set() methods的包装器被更改了。 您将无法看到子类getter-setter方法API。 但是当你输回到子类(基本上展开)时,再次可以看到子类的getter setter方法。

对象在整个时间内保持不变。