Java 抽象类:强制子类定义常量

问题描述 投票:0回答:6

我有一个抽象类,我希望所有非抽象子类都根据实现定义一个常量 - 它主要是有关类实现的元数据。

在超类中:

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";

有没有办法强制类的实现声明常量?

java inheritance constants
6个回答
12
投票

您可以强制子类定义一个方法,该方法可以是该类的常量。

protected abstract String objectName();
protected abstract String objectDef();

注意:如果您有子类的子类,这些子类可能会“忘记”覆盖这些方法。


1
投票

这样是行不通的。我将它们定义为抽象函数:

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
,但我认为这是最接近你想要的。


1
投票

这是另一种方法。我喜欢它,因为它很严格,让我们可以将大部分代码(包括 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 构造函数的危险。


1
投票

可能还需要一个接口,因为你没有超类的合理默认值:

interface HasObjectNameAndDef {
    public String getObjectName();
    public String getObjectDef(); 
}

然后让您的实际类实现该接口。作为奖励,您将获得更灵活的测试。


0
投票

不。你不能。

您甚至无法在抽象超类中声明常量而不为它们分配具体值。在其他情况下你会得到一个错误。您应该在声明期间或类构造函数中初始化最终字段。

您可以声明将初始化变量的抽象方法(但这会更加混乱)。像这样:

protected String OBJECT_NAME = getObjectNameValue();

public abstract String getObjectNameValue();

但在这种情况下,你的变量和方法不应该是静态的。因为你不能将静态方法定义为抽象方法(查看此处的解释)。

或者你可以像Peter Lawrey建议的那样直接使用方法而不是变量,这样会更具可读性。


-1
投票

我知道你在说什么。

例如,我想要一个接口(我称之为 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();
方法。不那么优雅,也许也不那么有效,但你目前没有其他选择。

© www.soinside.com 2019 - 2024. All rights reserved.