编辑:从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 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, " , ")));
}
}
为什么不能在Java接口中定义静态方法?
实际上在Java 8中可以。
根据Java文档:
静态方法是与其中的类相关联的方法
它是定义的,而不是与任何对象。类的每个实例
共享它的静态方法
在Java 8中,接口可以有默认方法和静态方法。这使得我们更容易在库中组织helper方法。我们可以在同一个接口中保留特定于某个接口的静态方法,而不是在一个单独的类中。
默认方法示例:
list.sort(ordering);
而不是
Collections.sort(list, ordering);
静态方法的例子(来自doc本身):
public interface TimeClient {
// ...
static public ZoneId getZoneId (String zoneString) {
try {
return ZoneId.of(zoneString);
} catch (DateTimeException e) {
System.err.println("Invalid time zone: " + zoneString +
"; using default time zone instead.");
return ZoneId.systemDefault();
}
}
default public ZonedDateTime getZonedDateTime(String zoneString) {
return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
}
}
有几个答案讨论了可覆盖静态方法概念的问题。然而,有时你会遇到一种模式,它似乎正是你想要使用的。
例如,我使用对象关系层,该层有值对象,但也有用于操作值对象的命令。由于各种原因,每个值对象类都必须定义一些静态方法,以便框架找到命令实例。例如,要创建一个Person,你可以这样做:
cmd = createCmd(Person.getCreateCmdId());
Person p = cmd.execute();
通过ID加载Person
cmd = createCmd(Person.getGetCmdId());
cmd.set(ID, id);
Person p = cmd.execute();
这是相当方便的,但它有它的问题;值得注意的是,静态方法的存在不能在接口中强制执行。接口中可覆盖的静态方法正是我们所需要的,只要它能以某种方式工作。
EJBs solve this problem by having a Home interface; each object knows how to find its Home and the Home contains the "static" methods. This way the "static" methods can be overridden as needed, and you don't clutter up the normal (it's called "Remote") interface with methods that don't apply to an instance of your bean. Just make the normal interface specify a "getHome()" method. Return an instance of the Home object (which could be a singleton, I suppose) and the caller can perform operations that affect all Person objects.