为什么通过该方法返回子类对象来调用超类变量?

时间:2017-06-14 09:44:38

标签: java

我知道变量没有多态性。如果我们执行新的Subclass()。x,则在运行时将打印值20。 但是这里

Parent p = new Child();   
p.getObject();
子类的getObject()将被调用,因为子类的getObject将覆盖超类的getObject()。因此子类方法getObject()返回新的Child(),因此打印的值应该是Child.x的值。但是输出是10.为什么x的值是超类的值?我知道有些帖子与此有关但不完全在任何地方都有解释。请帮忙。

class MainClass {
     public static void main(String[] args) {
      Parent p = new Child();
      System.out.println(p.getObject().x);
     }
    }

    class Parent {
     int x = 10;

     public Parent getObject() {
      return new Parent();
     }
    } 

    class Child extends Parent {
     int x = 20;

     public Child getObject() {
      return new Child();
     }
    }

3 个答案:

答案 0 :(得分:0)

您正在访问类x中的变量Parent,因为p.getObject()声明类型Parent

BTW:访问对象内部的变量直接违反了OOP的最基本原则:信息隐藏/封装!您应该仅为数据传输对象/ ValueObjects 执行此操作,这些对象充当纯数据容器并且没有自己的业务逻辑。甚至在那里你应该使用getter / setter方法而不是直接变量访问...

答案 1 :(得分:0)

完全是关于Java中的内存分配

拥有Parent p = new Child();意味着您在堆上创建了一个类Child的对象,并且对它的引用命名为p,但是这个引用意味着对类Parent的对象进行操作。 所以你要分配一个Child类型的对象,但是引用是用Parent运行的。

这意味着,引用将无法看到Child的x属性。它只会看到Parent属性。

检查thisthis以及

答案 2 :(得分:0)

您所做的是阴影。如果使用已在可达范围内定义的名称声明变量,则该变量将隐藏(隐藏)已定义的变量。如果要使用外部作用域中的变量,则必须编写该变量的绝对路径或使用对该变量唯一的访问器。

public class A {
    int a;

    public A(int a) {
        System.out.println(a); // arg "a" has shadowed class field
        System.out.println(this.a);

        // that's why we are using this assignment:
        this.a = a;
    }
}

你的例子也是如此。 child.x已隐藏parent.x字段。如果对象引用是Child类型i。即Child c = new Child();,默认情况下,将使用最近的可到达变量xChild.x)。如果您的对象引用是Parent类型i。即Parent p = new Parent();,然后将再次使用最近的可到达xParent.x)。这同样适用于Parent p = new Child();,因为pnew Child,但已提升为Parent类型,因此p.x将显示Parent.x值。

您必须记住,多态不适用于类字段。除非它包含在某个getter中,否则不能覆盖字段值。

因此,如果您需要覆盖显示的值,则必须将此值包装在某个getter中,该getter将被Child类覆盖:

public class Test {
    public static void main(String[] args) {
        Parent p = new Child();
        System.out.println(p.getObject().getValue()); // 20
        System.out.println(p.getValue()); // 20
    }

    static class Parent {
        int x = 10;

        public int getValue() {return x;}

        public Parent getObject() {return new Parent();}
    }

    static class Child extends Parent {
        int x = 20;

        @Override
        public int getValue() {return x;} // return Child.x

        @Override
        public Child getObject() {return new Child();}
    }
}