摘要 类 - 超级构造函数 (Java)

Abstract Classes - Super Constructor (Java)

我有一个非常简单的问题:

假设我有一个抽象 class 代表酒吧里的一个人。

public class Person {
    protected String firstName;
    protected String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

而且我还有 2 个 class 扩展 Person,假设一个 class 用于调酒师,一个 class 用于顾客。

在客户的class中,我还想要一个代表他年龄的int作为一个字段。在调酒师 class 中,我们没有。

此外,对于客户 class,我想要一个方法 isAdult()。

public class Bartender extends Person {
    public Bartender(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

public class Customer extends Person {
private int age;    

    public Customer(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
}

我现在有两个问题:

1) 这不起作用,因为我收到消息 "Implicit super constructor Passenger() is undefined. Must explicitly invoke another constructor"。 这到底是什么意思? 2) 对于方法 isAdult(),我觉得最好的方法是在抽象中实现它 class Person like this:

public abstract boolean isAdult();

然后为始终返回 true 的调酒师和检查年龄的顾客实施它。

另一种方法是像这样直接从 class 人实施它:

public boolean isAdult() {
    return (this instanceof Bartender || age > 18);
}

那行得通吗?哪种方式更好?

Person 有一个使用构造函数定义的参数,没有默认的无参数构造函数。由于子 class 的超级构造函数必须始终在子构造函数中调用,并且由于 Person 没有默认构造函数,因此您必须 明确地 在子构造函数中调用它:

public Bartender(String firstName, String lastName) {
    super(firstName, lastName);

    // don't do this:
    // this.firstName = firstName;
    // this.lastName = lastName;
}

public Customer(String firstName, String lastName, int age) {
    super(firstName, lastName);
    this.age = age;
}

关于 isAdult(),您可以只在 Customer class 中使用此方法,而不在 Bartender 中使用。或者,如果 super 必须有这个方法,如果有人在 Bartender 上调用它,你可以抛出异常,因为它不应该那样调用。

对于你的第一个问题,请注意一些事情:当你创建一个 class 时,它会自动为你创建一个 class 的默认构造函数。如果你创建另一个构造函数,你 必须 所以你自己创建默认的("default" 这里是没有参数的),因为 Java 认为你知道你在做什么现在。所以,只需将它添加到 Person class:

public Person(){}

第一个问题,参见Hovercraft Full Of Eels的回答;对于你的第二个问题,我认为你应该只给 Person 一个 "age" 属性 (每个人都有一个年龄)和逻辑 isAdult 实现。如果 Bartender 真的是 Person,它应该有年龄。因此,我认为您一开始就不能假设 Bartender 是成年人。在任何调用 Person#isAdult 的逻辑中,在 PersonBartender.

的情况下假设 true

1的答案:Java实际上总是调用超类的构造函数。例如:

class Super{
}

class Base extends Super{
     public Base(){
          //super() will always be called implicitly if a defaultconstructor is provided by Super

          //do something else
     }
}

这是完成的,因为基类的结构由基类的结构和超类的结构组成。如果不通过调用超类的构造函数来初始化超类的结构,则可能会发生错误。由于 Person 不提供默认构造函数,但无论如何都需要初始化,因此您必须使用两个参数显式调用超构造函数。

答案2: 两者都可以正常工作,但我(以及我希望的其他所有人)强烈建议在派生 类 中单独实施它,以保持一切可扩展、干净、可读以及出于其他数千个原因。

你问题的第二部分: 在 superclass 中使 isAdult() 抽象,在 children classes 中提供具体实现。如果事实证明 children class 中的几个具有类似的实现,那么您可以考虑将该实现放在 parent class 中并适当地覆盖。

Parent classes 不应该知道他们的 children classes,所以让 parent 检查 instanceof children是要避免的。