摘要 类 - 超级构造函数 (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
的逻辑中,在 Person
是 Bartender
.
的情况下假设 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是要避免的。
我有一个非常简单的问题:
假设我有一个抽象 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
的逻辑中,在 Person
是 Bartender
.
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是要避免的。