假设我有一个抽象的父类:
public class Foo extends Bar {
public int count = 1;
}
现在我有几个具体的子类。假设一个是:
count
现在我想迭代扩展抽象类的子集合。当我问他们List<Bar> l = new ArrayList<Bar>();
l.add(new Foo());
for (Bar b : l) {
System.out.println(b.count.toString()); // This always gives 0.
}
的值时,我发现我得到的是父母的初始值,而不是孩子初始化的值:
76
我显然使用了错误的类模型。什么是正确的方法,以便我可以获得子类初始化的值?
答案 0 :(得分:4)
您的迭代引用类型Bar
,作为List
的参数化类型。
因此,它会count
Bar
的{{1}}属性,隐藏在Foo
的{{1}}之内。
这就是你得到count
的原因。
如果您想要动态变量解析,请实现并覆盖返回0
的方法。
如果您还使用更合适的访问修饰符设置count
,那么这将有助于您的封装设计。
最后的注释
引用您的评论:
我更喜欢坚持使用字段,因为我有很多这些字段
为您的字段实现getter和setter应该是微不足道的。
事实上,一旦宣布了字段,就可以通过在任何可敬的IDE中遵循快速向导来获得自动草稿或完全实现的方法。
作为一般规则,如果您的字段是可变的,您可以考虑不使用模板getter。
作为另一个一般规则,如果您的字段在设置之前需要验证,您可以考虑不使用按原样实现的模板设置器。
我建议您仔细研究encapsulation的概念。
答案 1 :(得分:1)
Access to fields在编译时解析。没有像字段覆盖的概念,只有字段阴影:Foo
中的 count 字段会影响继承的{{1} } {} {}}中的字段。
为避免阴影和混淆,您应该将继承类中的字段重命名为count
。
尽管如此,如果您要打印Bar
中定义的fooCount
字段,您可以这样做:
count
当然,正如其他答案中所建议的那样,您应该重新考虑这种设计是否良好(并且第一个可能不太好的信号是使用Foo
运算符),并使用多态来实现相同的效果目标以更易读和可维护的方式。
答案 2 :(得分:0)
作为Mena答案的补充,我想指出在子类中隐藏超类属性通常是一团糟,显然不是一个好的面向对象设计。
如果您希望Foo
和Bar
个对象具有不同的值,为什么不使用构造函数以不同方式初始化count
字段?这是达到您要求的最直接方式。
public class Bar {
public int count ;
public Bar() {
count = 0;
}
}
public class Foo extends Bar {
public Foo() {
count = 1
}
}
使用此代码,您可以轻松利用多态来循环List<Bar>
并收集count
,而无需强制转换,或者不为Bar
的每个子类定义getter