【问题标题】:java how to get superclass method to modify subclass fieldjava如何获取超类方法来修改子类字段
【发布时间】:2011-06-29 19:16:56
【问题描述】:

我有两个类 A 和 B 如下

public class A {
    Number x;

    public A (){
        x = 10;
    }

    public void setX(Number x){

        //do a bunch of super complicated and lengthy stuff
        // afterwards set x
        this.x = x;
    }
}

public class B extends A{
    int x;

    public B(){
        super();
    }

    public void setX(int x){
        super.setX(x);
    }

    public int getX(){
        return x;
    }
}

我的主要是

public class Main {
    public static void main(String[] args) {
        B test = new B();
        test.setX(9);
        System.out.println(test.getX());
    }
}

输出为 0。我希望它为 9。我意识到在这个简单的示例中,我可以在 B 中的方法中写 x = 9,但如果它是一个更复杂的方法,我不想重写所有已经在我的超类方法中编写的代码,那么我将如何实现呢?

编辑:在子类 B 中,我故意调用我的 int 变量 x 来隐藏超类变量 x。假设超类中的 setX 方法在最终设置 x 之前做了很多其他的事情。我希望它设置子类的 x 。这可能吗?这是一个琐碎的例子。在我的实际问题中,它要复杂得多。

编辑:实际问题是这样的。我有一个名为ColorBinaryTree 的类,它是BinaryTree 的子类。唯一的区别是ColorBinaryTree 类有一个颜色字段,所以我可以实现一个红黑树。 BinaryTree 类对 parent、left 和 right 的引用,它们都是 BinaryTree 对象。 ColorBinaryTree 类具有相同的引用,但它们是 ColorBinaryTree 对象而不是 BinaryTree 对象。我有一堆操纵树的方法。一个例子如下

public BinaryTree<E> root() {
    if (parent == null) return this;
    else return parent.root();
}

在我的子类中,我需要重写它,以便我可以做协变返回类型并返回一个 ColorBinaryTree 对象。但是,如果我可以在我的子类方法中调用超类方法,那就太好了。但似乎如果我调用超类方法,它会查看超类的父字段。我希望它查看子类的父字段。

【问题讨论】:

    标签: java inheritance field hidden


    【解决方案1】:

    让我们从这两个变量被命名为x 的事实开始——就编译器而言,这完全是巧合。它不像 B.x "覆盖 A.x。如果你想要多态行为,你必须使用方法。

    现在你可以覆盖 B 中的 setX:

    @Override
    public void setX(Number x)
    {
        this.x = x.intValue();
    }
    

    您可能想让它调用super.setX()

    如果你能举一个更现实的例子会有所帮助 - 我会避免这样的设计开始......

    【讨论】:

    • 我认为将它们都命名为 x 是如何“隐藏”一个字段?
    • @jhlu87:它有效地将其隐藏在B 中的代码中。坦率地说,这通常不重要,因为通常你的字段应该是私有的,所以你不应该访问你的超类的字段。
    • @jhlu87:隐藏超类字段不会对您有所帮助。拥有两个有效地包含相同数据的变量是个坏主意。
    • @Jon Skeet,如果你说的是真的,那么我真的没有必要让 ColorBinaryTree 成为 BinaryTree 的子类。尽管如此,如果我这样做,我至少可以利用一种旋转的方法。当唯一的区别只是添加一个字符串字段时,必须复制和粘贴这么多代码似乎是错误的。
    • 您当然可以将ColorBinaryTree 设为BinaryTree 的子类。你只需要忍受这样一个事实,例如parent 是对 BinaryTree 的引用,而不是专门对 ColorBinaryTree 的引用。这很好,在正常情况下,因为即使你正在编写一个与节点的parent 交互的ColorBinaryTree 方法,它通常也可以通过BinaryTree 接口这样做,并依靠多态性在运行时。
    【解决方案2】:

    当您使用泛型时,您使用的是 Java 5。用更具体的返回类型覆盖方法怎么样:

    class BinaryTree<E> {
      public BinaryTree<E> root() {
        if (parent == null) return this;
        else return parent.root();
      }
    }
    
    class ColorBinaryTree<E> extends BinaryTree<E> {
      @Override
      public ColorBinaryTree<E> root() {
        return (ColorBinaryTree<E>)super.root();
      }
    }
    

    或者可以使用更复杂的通用解决方案:

    abstract class AbstractBinaryTree<E, T extends AbstractBinaryTree<E,T>> {
      T parent;
    
      public T root() {
        if (parent == null) return (T)this;
        else return parent.root();
      }
    }
    
    class BinaryTree<E> extends AbstractBinaryTree<E, BinaryTree<E>>{
    }
    
    class ColorBinaryTree<E> extends AbstractBinaryTree<E, ColorBinaryTree<E> {
    }
    

    【讨论】:

      【解决方案3】:

      您在子类中重新定义了 x。取出 int x 声明并删除“super”。 setX 方法的一部分,因此它只显示:“this.x = x”。

      你的问题的根源,是你改变了在类 A 中定义的 x,然后在类 B 中提供了初始化为 0 的值。

      【讨论】:

        【解决方案4】:

        您从子类中输出私有 int x 并在超类中设置 Number 变量。

        【讨论】:

          【解决方案5】:

          从您的 B 类中删除“x”变量。您的方法 getX() 正在返回该变量,而不是基类中的变量。

          【讨论】:

            【解决方案6】:

            如果没有自己的成员,这个解决方案怎么样(只要 A 中的 x 不是私有的):

            public class B extends A {
            
              public void setX(int x){
                super.setX(x);
              }
            
              public int getX(){
                return x.intValue();
              }
            }
            

            在类层次结构中具有相同命名的成员绝不是一个好的设计!

            【讨论】:

            • 查看我在底部的编辑,了解我更复杂的实际问题。我最初有这个,但我需要树引用也是 ColorBinaryTree 对象。这就是我再次宣布它们的原因。我使用了相同的名称,希望隐藏超类中的引用,这样我就可以利用继承的方法。
            • “我需要树引用也是 ColorBinaryTree 对象。”为什么?
            【解决方案7】:

            我自己刚才也遇到了同样的问题,当然你的问题也是。

            您可以做的一件事是重新初始化(不构造具有相同名称的新字段)ColorBinaryTree 类的构造函数中的字段 parentleftright,使其成为 ColorBinaryTree 对象.

            如果您的类确实是 BinaryTree 的子类并且这些字段不是私有的或包私有的,这应该是可能的。

            现在,这些字段将是 ColorBinaryTree 对象,但仍将被视为 BinaryTree 对象,因为这是它们在超类 (BinaryTree) 中声明的内容。为了克服这个问题,您可以在必要时将它们简单地转换为 ColorBinaryTree 对象。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2017-05-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-06-29
              • 1970-01-01
              相关资源
              最近更新 更多