17

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

abstract final static String Name;

但我仍然抱有希望,因为 Java 在带有 serialVersionUID的Serializable 接口中使用了类似的东西。有人知道他们是怎么做到的吗?是否可以在我自己的课堂上重现它?

4

5 回答 5

12

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

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不是Serializable接口的一部分。

于 2019-03-19T10:43:02.800 回答
10

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

检查serialVersionUID字段在工具中是硬编码的。一个例子是 使用反射java.io.ObjectStreamClass.getSerialVersionUID()加载值的 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;
}
于 2019-03-19T10:38:53.290 回答
2

我不推荐它,但如果你非常需要它,你可以在Checkstyle中创建一个正则表达式检查并强制人们实现静态变量

于 2019-03-19T10:52:17.640 回答
1

当实现的类Serializable没有serialVersionUID您在 IDE 中看到的小消息并且在编译时是由javac. 如果你想创建类似的东西,你可以,但过程似乎很复杂。解决方案就在这个答案中。

它们进行了详细介绍,但总体思路是创建注释和注释处理器,并在编译期间使用注释处理器。我猜你可以使用反射(或者......不是反射,因为它是编译时间?)来查看带注释的类是否包含你想要的字段。

于 2019-03-19T15:04:50.220 回答
0

这是我发现模拟它的最佳方法。Javadoc 防止防止有点糟糕的扩展......但 id 子类没有 NAME 它只会无法执行

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";
}
于 2019-03-19T13:26:07.830 回答