Java 中的接口没有成员字段,只有方法。 (讨论here。)换句话说,接口定义行为,但不定义状态。
您可以通过在接口上声明 JavaBeans 样式的访问器方法 get… 和 set… 来暗示属性存在。
如果您想确保每个对象都有自己的具有特定名称的特定类型的成员字段,那么可以,正如您所建议的那样,使用该字段定义一个抽象类。
当然,您可以同时做到这两个:编写一个包含成员字段的抽象类,该成员字段实现需要访问器方法的接口。两者都做是否是个好主意取决于您的具体情况。
以下是一个可能的示例场景,它同时具有 (a) 一个带有成员字段的抽象类,以及 (b) 一个需要 getter/setter 访问器方法的接口。我不完全确定我在这个例子中的逻辑的完整性,但希望它传达了一般的想法。
车辆种类繁多。有些在公共街道上使用是合法的,有些则不是。街头合法的一方面是拥有Vehicle identification number (VIN)。
让我们定义车辆的层次结构。
-
Vehicle 是祖父超类,是抽象的。
-
GoKart 是 Vehicle 的一个子类,也是抽象的,在街上开车是不合法的。
-
Vin 是代表我们车辆识别号 (VIN) 类型的记录。
-
Car 是 Vehicle 的另一个子类,也是抽象的。但是汽车在街上行驶是合法的。这个抽象类带有一个protected 类型的Vin 类成员,由任何子类继承。
- 为了将
Car 类及其子类标记为合法,我们定义了一个StreetLegal 接口。该接口定义了一对方法来暗示属性Vin 存在于所有实现该方法的类中。
- 为了将这一切整合在一起,我们为一种特定类型的汽车提供了一个示例具体类
HondaElement。
package work.basil.example.cartalk;
public abstract class Vehicle
{
}
package work.basil.example.cartalk;
// Not street-legal.
// https://en.wikipedia.org/wiki/Go-kart
public abstract class GoKart extends Vehicle
{
public boolean hasRemoteSpeedControl ;
}
package work.basil.example.cartalk;
// VIN = Vehicle identification number.
// https://en.wikipedia.org/wiki/Vehicle_identification_number#North_American_check_digits
public record Vin(String countryCode, int checkDigit, String serialNumber)
{
// Add constructor to validate data.
}
package work.basil.example.cartalk;
public abstract class Car extends Vehicle implements StreetLegal
{
protected Vin vin ;
}
package work.basil.example.cartalk;
public interface StreetLegal
{
public Vin getVin ( );
public void setVin ( Vin vin );
}
package work.basil.example.cartalk;
public class HondaElement extends Car implements StreetLegal
{
public HondaElement ( Vin vin )
{
this.vin = vin; // Accessing member field defined on abstract superclass `Car`.
}
@Override
public Vin getVin ( )
{
return this.vin; // Accessing member field defined on abstract superclass `Car`.
}
@Override
public void setVin ( Vin vin )
{
this.vin = vin; // Accessing member field defined on abstract superclass `Car`.
}
}