java中的抽象常量

java中的抽象常量,java,Java,我想创建一个未在超类中实现的常量,以便强制子类实现它。我发现()的最佳解决方案是创建一个将返回常量值的抽象方法。我认为这样做是不可能的: abstract final static String Name; 但我仍然有希望,因为Java在serialVersionUID中使用了类似的东西。有人知道他们是怎么做到的吗?是否可以在我自己的类中复制它?serialVersionUID接口不强制字段存在,因为接口不能强制字段存在。您可以声明一个实现了Serializable的类,它可以在没有seria

我想创建一个未在超类中实现的常量,以便强制子类实现它。我发现()的最佳解决方案是创建一个将返回常量值的抽象方法。我认为这样做是不可能的:

abstract final static String Name;

但我仍然有希望,因为Java在serialVersionUID中使用了类似的东西。有人知道他们是怎么做到的吗?是否可以在我自己的类中复制它?

serialVersionUID
接口不强制字段存在,因为接口不能强制字段存在。您可以声明一个实现了
Serializable
的类,它可以在没有
serialVersionUID
字段的情况下正常编译

检查
serialVersionUID
字段在工具中是硬编码的。一个例子是JDK方法,它加载带有反射的
serialVersionUID
值:

/**
 * Returns explicit serial version UID value declared by given class, or
 * null if none.
 */
private static Long getDeclaredSUID(Class<?> cl) {
    try {
        Field f = cl.getDeclaredField("serialVersionUID");
        int mask = Modifier.STATIC | Modifier.FINAL;
        if ((f.getModifiers() & mask) == mask) {
            f.setAccessible(true);
            return Long.valueOf(f.getLong(null));
        }
    } catch (Exception ex) {
    }
    return null;
}
/**
*返回给定类声明的显式串行版本UID值,或
*如果没有,则为null。
*/
私有静态长getDeclaredSUID(类别cl){
试一试{
字段f=cl.getDeclaredField(“serialVersionUID”);
int mask=Modifier.STATIC | Modifier.FINAL;
if((f.getModifiers()&掩码)=掩码){
f、 setAccessible(true);
返回Long.valueOf(f.getLong(null));
}
}捕获(例外情况除外){
}
返回null;
}

此类常量不能是
静态的
,因为
静态的
字段在类的所有实例之间共享,包括所有子类的实例。 以下是如何将其实现为非静态常量:

public abstract class Foo {
  public final String name; // Particular value to be defined in subclass

  protected Foo (String name) {
    this.name = name;
  }
}

public class Bar extends Foo {
  public Bar () {
    super ("Zoo"); // Here we define particular value for the constant
  }
}

顺便说一句,
serialVersionUID
不是可序列化接口的一部分。

我不推荐它,但如果您非常需要它,您可以创建一个regex签入并强制人们实现静态变量,这是我发现的模拟静态变量的最佳方法。Javadoc阻止一点到坏的扩展。。。但是id子类没有名称,它将无法执行

public abstract class Foo {
    protected final String NAME;
    public Foo() {
        String name="";
        try {
            name = (String) this.getClass().getDeclaredField("NAME").get(name);
        } catch (NoSuchFieldException 
                 | SecurityException 
                 | IllegalArgumentException 
                 | IllegalAccessException e) {
            e.printStackTrace();
        }
        NAME = name;
    }
}

public class Bar extends Foo {
    public static final String NAME = "myName";
}

当实现
Serializable
的类没有
serialVersionUID
时,您在IDE中看到的小消息以及编译时是由
javac
发出的警告。如果你想创造这样的东西,你可以,但过程似乎很复杂。解决办法就在这里


它们非常详细,但总体思路是创建注释和注释处理器,并在编译期间使用注释处理器。我猜您可以使用反射(或者…不是反射,因为它是编译时?)来查看带注释的类是否包含所需的字段。

问题是如何使用serialVersionUID解决这个问题?所以这是有可能的……仅供参考,在可序列化的情况下,运行时需要的是
serialVersionUID
,而不是编译器。实现了
Serializable
且没有该字段的类可以很好地编译。此外,
serialVersionUID
对于运行时也不是必需的。如果它不存在,序列化机制会计算它。即使它不是强制性的,它仍然会请求它。SerialVersionUID不是我想要的确切解决方案,但它非常接近。@JulienMaret如果它不存在,您是否更关心发出警告,或者如果它不存在,您是否希望获得默认值?或者两者都有?你确定代码不会编译吗?您的代码看起来不仅可以编译,而且运行时不会出错,因为您捕获了异常?我想您应该在catch块中将
NAME
设置为
Foo.NAME
,对吗?这样,如果他们不“覆盖”它,它将使用“默认值”?为什么要将
name
引用的空
字符串
传递给(子)类声明的
get
方法?这显然不是这次行动的正确目标。当你检查了
NAME
是否存在时,你从中得到了什么?您是否知道,当您创建
Bar
的子类时,此代码将中断?@JulienMaret Checkstyle不仅仅是一个Eclipse插件。它也可以像Maven一样成为构建过程的一部分。我认为这不是一个好的解决方案,但我只想指出它实际上不是特定于IDE的。