Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从父类对象调用子类方法_Java_Inheritance - Fatal编程技术网

Java 从父类对象调用子类方法

Java 从父类对象调用子类方法,java,inheritance,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(){...} } 这只是我实际模式的简化版本。最

我有以下课程

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

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

class Teacher extends Person{
    String experience;
    void getExperience(){...}
}
这只是我实际模式的简化版本。最初我不知道需要创建的人的类型,因此处理这些对象创建的函数将general
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语句说“找不到getMultiple for QuestionOption”。OuestionOption有更多的子类,这些子类具有不同类型的方法,这些方法在子类中不常见(getMultiple在子类中不常见)

注意:尽管这是可能的,它根本不被推荐,因为它破坏了继承的理由。最好的方法是重新构造应用程序设计,以便不存在父到子依赖关系。父母不应该知道自己的孩子或他们的能力

然而。。您应该能够这样做:

void calculate(Person p) {
    ((Student)p).method();
}
安全的方法是:

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

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

我对此犹豫不决,但这里有一个无耻的插件,用于我写的一篇博文,该博文概述了在Java中实现变体类型的8种方法。它们都很差劲,因为Java在变量类型上差劲。到目前为止,唯一正确的JVM语言是Scala

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


更新:找到它。

为什么不亲自编写一个空方法,并在children类中重写它呢?并在需要时称之为:

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

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

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

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


在您的示例中,您可以将
Person
抽象化,并在
Student
Teacher
的实例上使用
getName()
,可以找到一种可能的解决方案

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......
  }
 }
}

我也遇到过同样的情况,我找到了一个解决办法,有点工程学,如下所示--

  • 您必须在父类中使用不带任何参数的方法,并使用--

    Class<? extends Person> cl = this.getClass(); // inside parent class
    
  • 在这种情况下,如果您通过子类对象调用父方法,“this”指针将引用子类对象

  • 您可能需要使用的另一个对象是Object obj=cl.newInstance()


  • 如果你还是在什么地方绊倒了,请告诉我。

    你有什么共同的想法吗?您需要找到一种方法来表示联合概念中每个子类的细节。然后,您将能够在
    Person
    中定义一个方法,并使用适当的行为在子类中重写该方法?为什么不在每个子类中实现
    calculate
    方法?那么
    calculate
    的Person参数是什么?如果这是计算的目标,可能它应该是
    calculate()
    ,然后用
    this
    做点什么(这对重写子类中的方法很有用)。这个问题需要更多信息-它不完整。请确切地说明您正在尝试做什么,以及您看到了哪些语法错误!类在java中是一个保留字,您必须为学生的眼睛使用另一个名称!如果可以避免,就不应该这样做。但是,如果绝对无法避免从父类代码调用子类中的方法,则可以这样做。是什么让您认为绝对无法避免呢?+1是一个很好的答案。如果你也指出这是一个不好的方法,OP最好重新思考他的类层次结构。是的,肯定不是这样,但我只是想指出一个可能的选择。。顺便说一句,我们在答案中添加了警告说明。@Keppil几乎所有事情都是可行的,但这并不意味着通过解决他的问题我们真的在帮助他。一个糟糕的设计会有后果,在我看来,我们应该帮助有一个干净的设计。谢谢你的回复。我在某个地方读到instanceof是导致很多bug的雷区之一。如果我使用它,在编码时应该注意什么?是的,在一个类中有许多
    instanceof
    通常不是一个好的OO实践,但在您有重复的类/接口名称或通过不同的类加载器加载它之前,它不应该导致任何错误。您好,欢迎使用堆栈溢出。尝试添加更多注释(而不是代码),解释作者为什么认为这是他/她正在寻找的答案。只有代码的答案不是很好的答案。非常感谢。
    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();
    
    
       }
       }
    
    cl.getDeclaredFields(); cl.getField("myfield"); // and many more
    
    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();
    
    
       }
       }