【问题标题】:How to access a child's inherited member from a parent's method如何从父母的方法访问孩子的继承成员
【发布时间】:2016-02-15 16:42:12
【问题描述】:

如何访问在其超类中声明的子类的字符串变量?

我有类似这样的课程:

public class Parent {
  public void display() {
    // displays A
  }
}

public class Child1 extends Parent {
}

public class Child2 extends Parent {
}

Parent p1 = new Child1();
Parent p2 = new Child2();

p1.display(); // Currently displaying parent value of A
p2.display(); // Currently displaying parent value of A

我如何确保在这个 display() 中,p1p2 都使用它们自己的 A 值,而不是父类?

【问题讨论】:

  • 如果Parent 类不是抽象类,则创建一个具有参数(String a) 的构造函数。然后从子类调用super(A)
  • 你能改写你的问题吗,因为我不明白你的意思
  • 我已尝试编辑问题。很抱歉,这是一个完整的重写,但原版很难理解。如果我弄错了,则回滚编辑(或只是更新我的编辑)。
  • + to @WyattLowery 评论因为可测试性倡导者谴责构造函数偷偷做某事。这使得测试变得困难。
  • 您是否有指向谴责构造函数的可测试性倡导者的链接?我是可测试性倡导者,我不谴责构造函数。

标签: java class oop virtual abstract


【解决方案1】:

(我正在回答这个问题,因为我已经对其进行了编辑;如果我误解了这个问题,我深表歉意。)

只要您不使用静态成员,所需的行为就是正常行为。在超类中定义需要的成员为protected;三个类中的任何一个的每个实例都将为其使用自己的值。

public class Parent {
  protected string name;

  public Parent() {
    name = "Parent's value";
  }

  public void setName(string newValue) {
    name = newValue;
  }

  public void display() {
    System.out.println(name);
  }
}

public class Child1 extends Parent {
  public Child1() {
    name = "Child1's value";
  }
}

public class Child2 extends Parent {
  public Child2() {
    name = "Child2's value";
  }
}

public static void main() {
  new Parent().display();
  new Child1().display();
  Child2 c2 = new Child2();
  c2.display();
  c2.setName("New name!");
  c2.display();
}

这会产生预期的输出:

Parent's value
Child1's value
Child2's value
New name!

【讨论】:

  • 如果变量是构造函数的一部分,它会强制子类在实例化时总是使用不同的变量;你认为这限制了灵活性吗?我想知道您的 cmets 在父级中使用 getName() 方法并覆盖它,如我的回复中所述。
  • 在父级中使用getName() 就可以了。但是有多个name 成员的声明或多个getName() 方法的定义是没有意义的。它们都可以在 Parent 中完成。子类不需要任何特殊代码。
  • “如果变量是构造函数的一部分,它将强制子类在实例化时始终使用不同的变量”。这是不正确的,它不会强制执行任何操作。您可能有一个 setName() 方法或直接使用该属性。在我的示例代码中,Child1Child2 直接更新 name 属性。您不需要其他变量。
  • "如果变量是构造函数的一部分,它会强制子类在实例化时总是使用不同的变量;你认为这限制了灵活性吗?" ...它没有,或者至少不需要。这个问题的答案不可能一概而论。你有一个问题要解决 -> 你开发了一个问题域 -> 你开发了一个服务于你的问题域的对象模型。如果您的对象模型中存在由子类中不同构造函数类型支持的“是”关系,那么您已经完成了您应该做的事情。
  • @PaulHicks,scottb:抱歉。我的意思是,如果“变量是构造函数 arg”,而不是“内部构造函数”。
【解决方案2】:

或者,如果有获取 A 值的方法,例如 class Parent 中的 getA(),则覆盖每个 class Child1class Child2 中的方法以返回它们各自的 A 值。

我重用了@paul-hicks 的示例,并在下面演示了我的方法:

public class Parent
    ...
    public void display() {
      System.out.println(getA());
    }

    protected String getName() {
      return "parent";
    }
}

class Child1 {
   ...
   protected String getName() {
      return "child1";
   }
}

class Child2 {
   ...
   protected String getName() {
      return "child2";
   }
}

【讨论】:

  • 这个版本不使用任何字段/成员,只是常量。这是极其不灵活的。如果getName() 实际上会返回一个name 成员,那么它与我的答案相同。出于示例的目的,我只是采用了一个快捷方式:我使用了受保护的成员而不是访问器。相同但不同。
  • @PaulHicks 当您指出我的版本不使用字段/成员时,我意识到我离题了。你已经为提出这个问题的人编写了一个示例代码,我离题了它的设计方面。是的,一模一样。
【解决方案3】:

有一种非常常见的方法可以做到这一点。这是一个java“模式”。该技术是在面向对象设计中使用 getter/setter 方法的一个重要示例。

在父类中为值 A 声明抽象 getter/setter 方法在子类中完全定义它们。父级普遍使用 getter/setter 来访问值。

这样,父类和子类将始终使用在子类中声明、管理和更新的“A”值。 getter 和 setter 不能是静态的(当然,这是没有意义的)。这种方法允许父类和子类保持独立,并且可以以非常灵活和干净的方式修改/调整子类。特别是,子类不需要主动维护 A,并且可以以 JIT(即时)方式计算、仔细检查或委托对 A 的请求。

完整示例:

public abstract class Parent {
  // These two methods must be overridden by all child classes. Compiler enforces that.
  public abstract int getA();
  public abstract int setA( int newA );
        // This display routine utilizes the *childs* a
  public void display() { someoutput.write( this.getA() ); }
}

public class Child1 extends Parent {
  SomeFancyOrPartularFormOfA a = null; // a Jazzy type of A, used by parent.
  @Override // Let java and IDEs know we intend to override it.
  public int getA() { return( this.a.gatherorcalcA() ); }
  @Override // Let java and IDEs know we intend to override it.
  public int setA( int newA ) { this.a.setorincorporateA( newA ); }
   . . .
}
public class Child2 extends Parent {
  Integer a = 0;  // A more mundane type of A, still used by parent.
  @Override // Let java and IDEs know we intend to override it.
  public int getA() { return( this.a ); }
  @Override // Let java and IDEs know we intend to override it.
  public int setA( int newA ) { this.a = newA; }
   . . .
}

【讨论】:

  • 好莱坞原理/模板方法模式?
  • 是的,这是模板方法的缩小版,由 4 个“设计模式”组成。在这个更简单的变体中,子类重新定义了数据的存储和管理,而不是算法本身。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-07
  • 1970-01-01
相关资源
最近更新 更多