Java抽象类字段覆盖

时间:2013-03-09 14:25:09

标签: java class override field abstract

我有一个应该实现公共字段的抽象类,这个字段是一个接口或另一个抽象的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允许我在这种情况下编译)怎么办?

谢谢!

6 个答案:

答案 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将隐藏超类的fieldoverriding没有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
    }
}