从父类对象调用子类方法

我有以下课程

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

注意:虽然这是可能的,但它完全没有被推荐,因为它破坏了inheritance的原因。 最好的方法是重新构建应用程序设计,以便不存在父对子依赖关系。 父母不应该知道自己的孩子或他们的能力。

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

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

安全的方式是:

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

父类不应该具有子类的知识。 您可以实现方法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 abstract,并在StudentTeacher instanced上使用getName()

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

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

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

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

更新 :在这里找到它。

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

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

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

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

  1. 您必须在父类中使用您的方法而不使用任何参数并使用 – –

     Class cl = this.getClass(); // inside parent class 
  2. 现在,使用’cl’,您可以使用 – – 访问所有子类字段及其名称和初始值

     cl.getDeclaredFields(); cl.getField("myfield"); // and many more 
  3. 在这种情况下,如果通过子类对象调用父方法,则“this”指针将引用子类对象。

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

如果你还在某个地方被困住,请告诉我。

一种可能的解决方案是

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