我有以下课程
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在子节点中不常见)
答案 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)
我有同样的情况,我找到了一个方法,如下工程 -
您必须在没有任何参数的父类中使用您的方法并使用 - -
Class<? extends Person> cl = this.getClass(); // inside parent class
现在,使用'cl',您可以使用 - -
访问所有子类字段及其名称和初始值cl.getDeclaredFields(); cl.getField("myfield"); // and many more
在这种情况下,如果您通过子类对象调用父方法,那么'this'指针将引用您的子类对象。
您可能需要使用的另一件事是Object obj = cl.newInstance();
让我知道你是否仍然被困在某个地方。
答案 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......
}
}
}