编辑:从Java 8开始,静态方法现在被允许出现在接口中。

下面是例子:

public interface IXMLizable<T>
{
  static T newInstanceFromXML(Element e);
  Element toXMLElement();
}

当然这行不通。但为什么不呢?

其中一个可能的问题是,当你调用:

IXMLizable.newInstanceFromXML(e);

在这种情况下,我认为它应该只调用一个空方法(即{})。所有子类都必须实现静态方法,所以在调用静态方法时它们都没问题。那为什么不可能呢?

编辑:我想我正在寻找比“因为这就是Java”更深刻的答案。

静态方法不能被覆盖是否有特殊的技术原因?也就是说,为什么Java的设计者决定让实例方法可重写,而不是静态方法?

编辑:我的设计的问题是我试图使用接口来执行编码约定。

也就是说,接口的目标有两个:

我希望IXMLizable接口允许我将实现它的类转换为XML元素(使用多态性,工作正常)。 如果有人想创建实现IXMLizable接口的类的新实例,他们总是知道会有一个newInstanceFromXML(Element e)静态构造函数。

除了在界面中添加注释之外,还有其他方法可以确保这一点吗?


当前回答

注释编辑:从Java 8开始,静态方法现在被允许出现在接口中。

这是正确的,静态方法自Java 8以来就被允许在接口中,但您的示例仍然不能工作。你不能只是定义一个静态方法:你必须实现它,否则你会得到一个编译错误。

其他回答

“是否有一个特殊的原因,静态方法不能被覆盖”。

让我把这个问题重新定义一下。

“在编译时解析的方法不能在运行时解析,是否有特殊原因?”

或者,更完整地说,如果我想在没有实例的情况下调用一个方法,但知道这个类,我怎么能根据我没有的实例来解析它呢?

如果没有泛型,静态接口是无用的,因为所有静态方法调用都是在编译时解析的。所以,它们没有真正的用处。

对于泛型,它们可以使用——无论是否使用默认实现。显然需要重写等等。然而,我的猜测是,这样的用法不是很面向对象(正如其他答案迟钝地指出的那样),因此被认为不值得付出努力来有效地实现它们。

虽然我意识到Java 8解决了这个问题,但我认为我应该加入我目前正在研究的一个场景(锁定在使用Java 7),在这个场景中,能够在接口中指定静态方法将会很有帮助。

I have several enum definitions where I've defined "id" and "displayName" fields along with helper methods evaluating the values for various reasons. Implementing an interface allows me to ensure that the getter methods are in place but not the static helper methods. Being an enum, there really isn't a clean way to offload the helper methods into an inherited abstract class or something of the like so the methods have to be defined in the enum itself. Also because it is an enum, you wouldn't ever be able to actually pass it as an instanced object and treat it as the interface type, but being able to require the existence of the static helper methods through an interface is what I like about it being supported in Java 8.

下面的代码说明了我的观点。

接口定义:

public interface IGenericEnum <T extends Enum<T>> {
    String getId();
    String getDisplayName();
    //If I was using Java 8 static helper methods would go here
}

一个枚举定义的例子:

public enum ExecutionModeType implements IGenericEnum<ExecutionModeType> {
    STANDARD ("Standard", "Standard Mode"),
    DEBUG ("Debug", "Debug Mode");

    String id;
    String displayName;

    //Getter methods
    public String getId() {
        return id;
    }

    public String getDisplayName() {
        return displayName;
    }

    //Constructor
    private ExecutionModeType(String id, String displayName) {
        this.id = id;
        this.displayName = displayName;
    }

    //Helper methods - not enforced by Interface
    public static boolean isValidId(String id) {
        return GenericEnumUtility.isValidId(ExecutionModeType.class, id);
    }

    public static String printIdOptions(String delimiter){
        return GenericEnumUtility.printIdOptions(ExecutionModeType.class, delimiter);
    }

    public static String[] getIdArray(){
        return GenericEnumUtility.getIdArray(ExecutionModeType.class);
    }

    public static ExecutionModeType getById(String id) throws NoSuchObjectException {
        return GenericEnumUtility.getById(ExecutionModeType.class, id);
    }
}

通用枚举实用程序定义:

public class GenericEnumUtility {
    public static <T extends Enum<T> & IGenericEnum<T>> boolean isValidId(Class<T> enumType, String id) {       
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(enumOption.getId().equals(id)) {
                return true;
            }
        }

        return false;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String printIdOptions(Class<T> enumType, String delimiter){
        String ret = "";
        delimiter = delimiter == null ? " " : delimiter;

        int i = 0;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(i == 0) {
                ret = enumOption.getId();
            } else {
                ret += delimiter + enumOption.getId();
            }           
            i++;
        }

        return ret;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String[] getIdArray(Class<T> enumType){
        List<String> idValues = new ArrayList<String>();

        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            idValues.add(enumOption.getId());
        }

        return idValues.toArray(new String[idValues.size()]);
    }

    @SuppressWarnings("unchecked")
    public static <T extends Enum<T> & IGenericEnum<T>> T getById(Class<T> enumType, String id) throws NoSuchObjectException {
        id = id == null ? "" : id;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(id.equals(enumOption.getId())) {
                return (T)enumOption;
            }
        }

        throw new NoSuchObjectException(String.format("ERROR: \"%s\" is not a valid ID. Valid IDs are: %s.", id, printIdOptions(enumType, " , ")));
    }
}

因为静态方法不能在子类中重写,因此它们不能是抽象的。事实上,接口中的所有方法都是抽象的。

可以实现的是静态接口(而不是接口中的静态方法)。实现给定静态接口的所有类都应该实现相应的静态方法。你可以从任何Class clazz中获得静态接口SI

SI si = clazz.getStatic(SI.class); // null if clazz doesn't implement SI
// alternatively if the class is known at compile time
SI si = Someclass.static.SI; // either compiler errror or not null

然后你可以调用si.method(params)。 这将很有用(例如对于工厂设计模式),因为您可以从编译时未知类获得(或检查)SI静态方法实现! 动态分派是必要的,您可以通过扩展类(当通过静态接口调用时)来重写类的静态方法(如果不是final方法)。 显然,这些方法只能访问它们类的静态变量。