我有一个应该实现公共字段的抽象类,这个字段是一个接口或另一个抽象的classe。
类似的东西:
public abstract class GenericContainer {
public GenericChild child;
}
public abstract class GenericChild {
public int prop1=1;
}
public abstract class SpecialChild extend GenericChild {
public int prop1=2;
}
现在我有另一个专门的类容器:
public abstract class SpecialContainer extends GenericContainer {
public SpecialChild child=new SpecialChild(); //PAY ATTENTION HERE!
}
Java允许我编译它,并且我想象child
中的字段SpecialContainer
会自动重载child
的字段GenericContainer
...
问题是:
我对吗?孩子的自动“超载”会发生吗?
更重要的问题是,如果我有另一个这样的课程:
public class ExternalClass {
public GenericContainer container=new SpecialContainer();
public int test() {
return container.child.prop1
}
}
test()
会返回1还是2?我的意思是GenericContainer
容器字段prop1
将调用什么,通用或特殊?
如果特殊的prop1被声明为String(是的,java允许我在这种情况下编译)怎么办?
谢谢!
答案 0 :(得分:14)
在Java中,数据成员/属性不是多态的。重载意味着字段将具有不同的值,具体取决于它访问的类。子类中的字段将隐藏超类中的字段,但两者都存在。 根据引用类型调用字段,而方法用于实际对象。你可以亲自试试。
它被称为变量隐藏/阴影,详情请见here
答案 1 :(得分:10)
它不会覆盖任何内容,您只是将原始字段隐藏在当前类范围内。如果您使用带有子类型的变量,您仍然可以访问原始属性。例如:
abstract class GenericContainer {
public GenericChild child;
}
abstract class GenericChild {
public int prop1=1 ;
}
class SpecialChild extends GenericChild {
public int prop1=2;
}
class SpecialContainer extends GenericContainer {
public SpecialChild child;
}
public class Main {
public static void main( String ... args ) {
GenericContainer container = new SpecialContainer();
container.child = new SpecialChild();
System.out.println( container.child.prop1 );
SpecialChild child = (SpecialChild) container.child;
System.out.println( child.prop1 );
}
}
打印1然后打印2。
从SpecialChild
开始,您还可以使用super
上升一级:
class SpecialChild extends GenericChild {
public int prop1=2;
public int getOriginalProp1() {
return super.prop1;
}
}
答案 2 :(得分:2)
关于
....我想象一下,SpecialContainer中的字段“child”会自动重载GenericContainer的字段'child'...
没有。字段不会被覆盖,只有方法可以覆盖。
这就是为什么首选使用(可覆盖的)getter和setter方法来直接访问字段的原因之一。您的字段几乎都应该是私有的。
至于你的设计,你的SpecialContainer类不需要有一个SpecialChild字段,而是应该将SpecialChild对象放在GenericChild字段中。
答案 3 :(得分:1)
Java允许我编译这个,并且我想象中的字段“child” SpecialContainer会自动重载字段'child' GenericContainer ...
首先,继承不适用于变量。字段(Insatnce变量)不会在子类中被覆盖。如果它们标有public, protected or default
,它们只能在您的子类中可见。
答案 4 :(得分:1)
要回答您的问题,它会维护这两个实例。并且取决于您如何引用容器(通过abstract或impl)确定您所引用的变量。
public class Test {
public abstract class Container{
public Generic gen = new Generic();
}
public class ContainerImpl extends Container{
public GenericImpl gen = new GenericImpl();
}
public class Generic{
public int prop = 0;
}
public class GenericImpl extends Generic{
public int prop = 1;
}
public Test(){
Container c = new ContainerImpl();
System.out.println(c.gen.prop); // Outputs "0"
System.out.println(((ContainerImpl)c).gen.prop); // Output "1"
}
public static void main(String[] args) {
new Test();
}
}
手头上更大的问题是,为什么要设计这样的东西?我假设你是从理论角度问的。
我的2美分,这不是伟大的OO设计。最好将公共变量设为私有,并通过构造函数或属性设置器分配它们的值。原样,它会在您的代码中导致意外结果。
答案 5 :(得分:1)
为什么没有人观察该程序会抛出NullPointerException
。
具有相同名称的子类field
将隐藏超类的field
。 overriding
没有field
。覆盖仅适用于方法。
作者原始代码:
public abstract class GenericContainer {
public GenericChild child;
}
public abstract class GenericChild {
public int prop1=1;
}
public abstract class SpecialChild extend GenericChild {
public int prop1=2;
}
public abstract class SpecialContainer extends GenericContainer {
public SpecialChild child=new SpecialChild(); //PAY ATTENTION HERE!
}
public class ExternalClass {
public GenericContainer container=new SpecialContainer();
public int test() {
return container.child.prop1
}
}