从父类对象调用子类方法

时间:2012-07-13 08:01:43

标签: java inheritance

我有以下课程

class Person {
    private String name;
    void getName(){...}}

class Student extends Person{
    String class;
    void getClass(){...}
}

class Teacher extends Person{
    String experience;
    void getExperience(){...}
}

这只是我实际架构的简化版本。最初我不知道需要创建的人的类型,因此处理这些对象的创建的函数将通用Person对象作为参数。

void calculate(Person p){...}

现在我想使用这个父类对象访问子类的方法。我还需要不时访问父类方法,所以我不能使它抽象


我想我在上面的例子中简化了太多,所以这里是,这是实际的结构。

class Question {
  // private attributes
  :
  private QuestionOption option;
  // getters and setters for private attributes
  :
  public QuestionOption getOption(){...}
 }

 class QuestionOption{
 ....
 }
 class ChoiceQuestionOption extends QuestionOption{
 private boolean allowMultiple;
 public boolean getMultiple(){...}
 }

 class Survey{
  void renderSurvey(Question q) {
      /*
          Depending on the type of question (choice, dropdwn or other, I have to render
          the question on the UI. The class that calls this doesnt have compile time 
          knowledge of the type of question that is going to be rendered. Each question 
          type has its own rendering function. If this is for choice , I need to access 
          its functions using q. 
      */
      if(q.getOption().getMultiple())
        {...}
  }
 }

if语句说“找不到QuestionOption的getMultiple”。 OuestionOption有更多的子类,它们具有不同类型的方法,这些方法在子节点中不常见(getMultiple在子节点中不常见)

7 个答案:

答案 0 :(得分:28)

注意: 虽然这是可能的,但它完全没有被推荐,因为它破坏了继承的原因。最好的方法是重构您的应用程序设计,以便有 NO 父级到子级依赖项。父母不应该知道自己的孩子或他们的能力。

然而..你应该能够这样做:

void calculate(Person p) {
    ((Student)p).method();
}

安全的方式是:

void calculate(Person p) {
    if(p instanceof Student) ((Student)p).method();
}

答案 1 :(得分:7)

父类不应该了解子类。您可以实现方法calculate()并在每个子类中覆盖它:

class Person {
    String name;
    void getName(){...}
    void calculate();
}

然后

class Student extends Person{
    String class;
    void getClass(){...}

    @Override
    void calculate() {
        // do something with a Student
    }
}

class Teacher extends Person{
    String experience;
    void getExperience(){...}

    @Override
    void calculate() {
        // do something with a Student
    }

}
顺便说一下。你关于抽象类的陈述令人困惑。您可以调用抽象类中定义的方法,但当然只调用子类的实例。

在您的示例中,您可以Person为摘要,并在getName()Student的实例上使用Teacher

答案 2 :(得分:3)

这里的许多答案都建议使用“经典面向对象的分解”来实现变体类型。也就是说,其中一个变体可能需要的任何东西都必须在层次结构的基础上声明。我认为这是一种类型安全的,但通常非常糟糕的方法。您要么最终暴露所有不同变体的所有内部属性(大多数变体对于每个特定变体都是“无效”),或者最终使用大量过程方法混乱层次结构的API(这意味着您必须每次都重新编译)一个新的程序被设想了。)

我对此犹豫不决,但这是一篇无耻的插件,我写了一篇博文,概述了8种在Java中使用变体类型的方法。他们都很糟糕,因为Java很糟糕。到目前为止,唯一正确的JVM语言是Scala。

http://jazzjuice.blogspot.com/2010/10/6-things-i-hate-about-java-or-scala-is.html

Scala创作者实际上写了一篇关于八种方式中的三种的论文。如果我可以追踪它,我会用链接更新这个答案。

更新:找到它here

答案 3 :(得分:2)

为什么不在Person中编写一个空方法并在子类中覆盖它?并在需要时调用它:

void caluculate(Person p){
  p.dotheCalculate();
}

这意味着你必须在两个子类中使用相同的方法,但我不明白为什么这会成为一个问题。

答案 4 :(得分:1)

我有同样的情况,我找到了一个方法,如下工程 -

  1. 您必须在没有任何参数的父类中使用您的方法并使用 - -

    Class<? extends Person> cl = this.getClass(); // inside parent class
    
  2. 现在,使用'cl',您可以使用 - -

    访问所有子类字段及其名称和初始值
    cl.getDeclaredFields(); cl.getField("myfield"); // and many more
    
  3. 在这种情况下,如果您通过子类对象调用父方法,那么'this'指针将引用您的子类对象。

  4. 您可能需要使用的另一件事是Object obj = cl.newInstance();

  5. 让我知道你是否仍然被困在某个地方。

答案 5 :(得分:1)

class Car extends Vehicle {
        protected int numberOfSeats = 1;

        public int getNumberOfSeats() {
            return this.numberOfSeats;

        }

        public void  printNumberOfSeats() {
          //  return this.numberOfSeats;
            System.out.println(numberOfSeats);
        }


    } 

//Parent class

  class Vehicle {
        protected String licensePlate = null;

        public void setLicensePlate(String license) {
            this.licensePlate = license;
            System.out.println(licensePlate);
        }


   public static void main(String []args) {
       Vehicle c = new Vehicle();

      c.setLicensePlate("LASKF12341"); 

//Used downcasting to call the child method from the parent class. 
//Downcasting = It’s the casting from a superclass to a subclass.

      Vehicle d = new Car();
      ((Car) d).printNumberOfSeats();


   }
   }

答案 6 :(得分:0)

一种可能的解决方案是

class Survey{
  void renderSurvey(Question q) {
  /*
      Depending on the type of question (choice, dropdwn or other, I have to render
      the question on the UI. The class that calls this doesnt have compile time 
      knowledge of the type of question that is going to be rendered. Each question 
      type has its own rendering function. If this is for choice , I need to access 
      its functions using q. 
  */
  if(q.getOption() instanceof ChoiceQuestionOption)
  {
    ChoiceQuestionOption choiceQuestion = (ChoiceQuestionOption)q.getOption();
    boolean result = choiceQuestion.getMultiple();
    //do something with result......
  }
 }
}