21

我有以下课程

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 在子类中不常见)

4

7 回答 7

39

注意:虽然这是可能的,但完全不推荐这样做,因为它会破坏继承的原因。最好的方法是重构您的应用程序设计,以便没有父子依赖关系。父母永远不需要知道自己的孩子或他们的能力。

但是..你应该能够这样做:

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

一种安全的方法是:

void calculate(Person p) {
    if(p instanceof Student) ((Student)p).method();
}
于 2012-07-13T08:05:23.970 回答
11

父类不应该有子类的知识。您可以实现一个方法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 Teacher
    }

}

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

在您的示例中,您可以对and 的实例进行Person抽象和使用。getName()StudentTeacher

于 2012-07-13T08:26:06.973 回答
3

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

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

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

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

更新:在这里找到它。

于 2012-07-13T08:09:26.443 回答
2

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

  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();

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

于 2015-02-20T06:56:37.077 回答
2

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

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

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

于 2012-07-13T08:22:08.907 回答
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();


   }
   }
于 2018-10-04T09:25:55.677 回答
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......
  }
 }
}
于 2012-07-16T11:12:11.137 回答