很抱歉,如果之前已经出现过,但我没有看到另一个关于此问题的帖子。但如果有,请给我链接。
这里有一个简单的程序。当它运行时,它打印出“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在被投入酒吧后仍然存在。有人可以解释为什么会这样吗?
答案 0 :(得分:6)
即使你施放和取消它多次,实际物体也会保持不变 投射从不添加/删除/更改对象属性。
Bar b = new Foo();
此处引用的类型为Bar
,实际对象的类型为Foo
。由于Foo
扩展了Bar
,这意味着它还具有属性f
和t
(继承自Bar
)。
list.add((Bar) foo);
在这里你将它投射到Bar(Upasting)但实际对象没有改变。
(Foo) list.get(0);
此处您将其强制转换回Foo
仍为Foo
的对象,其t
和f
的原始值。
答案 1 :(得分:2)
多态性的工作原理并非如此。它不会从特定的对象中删除任何内容。 你可以这样思考:
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方法。
对象在整个时间内保持不变。