我有一个抽象类,我希望所有非抽象子类都根据实现定义一个常量 - 它主要是有关类实现的元数据。
在超类中:
protected static final String OBJECT_NAME;
protected static final String OBJECT_DEF;
然后在子类中:
protected static final String OBJECT_NAME = "awesome class";
protected static final String OBJECT_DEF = "an awesome class that is also great";
有没有办法强制类的实现声明常量?
您可以强制子类定义一个方法,该方法可以是该类的常量。
protected abstract String objectName();
protected abstract String objectDef();
注意:如果您有子类的子类,这些子类可能会“忘记”覆盖这些方法。
这样是行不通的。我将它们定义为抽象函数:
protected abstract String objectName();
protected abstract String objectDef();
在子类中:
private static final String OBJECT_NAME = "awesome class";
private static final String OBJECT_DEF = "bla";
protected String objectName(){
return OBJECT_NAME;
}
protected String objectDef(){
return OBJECT_DEF;
}
这些方法不是
static
,但我认为这是最接近你想要的。
这是另一种方法。我喜欢它,因为它很严格,让我们可以将大部分代码(包括 getter)放入父类中,使其子类保持整洁。
abstract class Parent {
private final int age;
private final String name;
Parent(int age, String name) {
this.age = age;
this.name = name;
}
int getAge() {
return age;
}
}
class Child extends Parent {
Child() {
super(18, "John");
// any other Child specific constructor logic
}
}
class Main {
public static void main(String[] args) {
var child = new Child();
System.out.println(child.getAge()); // Will print 18
}
}
注意:
Child
不会继承 Parent
的构造函数,因此在初始化 Child
时不存在意外使用 warng 构造函数的危险。
可能还需要一个接口,因为你没有超类的合理默认值:
interface HasObjectNameAndDef {
public String getObjectName();
public String getObjectDef();
}
然后让您的实际类实现该接口。作为奖励,您将获得更灵活的测试。
不。你不能。
您甚至无法在抽象超类中声明常量而不为它们分配具体值。在其他情况下你会得到一个错误。您应该在声明期间或类构造函数中初始化最终字段。
您可以声明将初始化变量的抽象方法(但这会更加混乱)。像这样:
protected String OBJECT_NAME = getObjectNameValue();
public abstract String getObjectNameValue();
但在这种情况下,你的变量和方法不应该是静态的。因为你不能将静态方法定义为抽象方法(查看此处的解释)。
或者你可以像Peter Lawrey建议的那样直接使用方法而不是变量,这样会更具可读性。
我知道你在说什么。
例如,我想要一个接口(我称之为 ExecutableList)有一个名为
USER_FRIENDLY_NAME
的常量字符串字段
public interface ExecutableList<T extends ExecutableList<T,E>,E> //This is type parameter
extends List<E>, //self referencing. Trust
Comparable<E>, //me, it has its uses.
{
/** This would declare a constant but leave it to sub-interfaces/classes to define it. */
abstract String USER_FRIENDLY_NAME;
//Define the rest of your interface
}
不幸的是,这在 Java 中是不可能的。当您在 Java 接口中声明字段时,它意味着修饰符
public
、static
和 final
。 Java 编程语言的未来更改可能允许添加 abstract
,从而使隐含修饰符 public abstract static final String USER_FRIENDLY_NAME;
但虽然您可以为此明确定义规则,但使用 abstract
这个词会令人困惑,因为 abstract
和 final
通常被理解为定义相反的含义。
我祈祷 Java 的未来版本能够实现这一点。我听说 Java 9 中将添加私有接口方法(用于在默认方法之间使用),但目前还没有关于该语言添加的消息。我确信首先需要考虑许多向后兼容性问题。如果 Oracle 的任何人读到这篇文章,请让我们在接口中声明常量并让继承类/接口定义它们!!!
与此同时,您唯一的选择是在接口或抽象类中定义
String getUserFriendlyName();
方法。不那么优雅,也许也不那么有效,但你目前没有其他选择。