为什么接口中没有静态方法,但是静态字段和内部类可以?[前Java8]
这里有几个问题是关于为什么不能在接口中定义静态方法,但没有一个解决基本的不一致性:为什么可以在接口中定义静态字段和静态内部类型,而不能定义静态方法 静态内部类型可能不是一个公平的比较,因为这只是生成新类的语法糖,但为什么是字段而不是方法 反对接口内静态方法的一个论点是,它破坏了JVM使用的虚拟表解析策略,但这不应该同样适用于静态字段,即编译器可以直接内联它吗为什么接口中没有静态方法,但是静态字段和内部类可以?[前Java8],java,interface,jls,Java,Interface,Jls,这里有几个问题是关于为什么不能在接口中定义静态方法,但没有一个解决基本的不一致性:为什么可以在接口中定义静态字段和静态内部类型,而不能定义静态方法 静态内部类型可能不是一个公平的比较,因为这只是生成新类的语法糖,但为什么是字段而不是方法 反对接口内静态方法的一个论点是,它破坏了JVM使用的虚拟表解析策略,但这不应该同样适用于静态字段,即编译器可以直接内联它吗 一致性是我所希望的,Java应该不支持接口中任何形式的静态,或者应该是一致的并允许它们 想到两个主要原因: Java中的静态方法不能被子类
一致性是我所希望的,Java应该不支持接口中任何形式的静态,或者应该是一致的并允许它们 想到两个主要原因:
在接口中只能声明静态final字段(很像方法,即使不包含“public”关键字,它们也是公共的,静态字段是带或不带关键字的“final”)
这些只是值,在编译时,它们将被复制到任何使用它们的地方,所以您永远不会在运行时真正“调用”静态字段。拥有一个静态方法不会有相同的语义,因为它会涉及调用一个没有实现的接口,而Java不允许这样做。在接口中声明一个静态方法是没有意义的。它们不能由正常调用MyInterface.staticMethod()执行。(编辑:由于最后一句话让一些人感到困惑,调用MyClass.staticMethod()正好执行MyClass上的staticMethod实现,如果MyClass是接口,则不可能存在!)如果通过指定实现类MyImplementor.staticMethod()来调用它们,则必须知道实际的类,因此,接口是否包含它是无关紧要的 更重要的是,静态方法永远不会被重写,如果您尝试执行以下操作:
MyInterface var = new MyImplementingClass();
var.staticMethod();
static的规则规定必须执行在声明的var类型中定义的方法。因为这是一个接口,所以这是不可能的
当然,您始终可以从方法中删除static关键字。一切都会好起来的。如果从实例方法调用,则可能必须抑制某些警告
为了回答下面的一些注释,您无法执行“result=MyInterface.staticMethod()”的原因是它必须执行MyInterface中定义的方法的版本。但是不能在MyInterface中定义版本,因为它是一个接口。它没有定义的代码。在Java 5之前,静态字段的常见用法是:
interface HtmlConstants {
static String OPEN = "<";
static String SLASH_OPEN = "</";
static String CLOSE = ">";
static String SLASH_CLOSE = " />";
static String HTML = "html";
static String BODY = "body";
...
}
public class HtmlBuilder implements HtmlConstants { // implements ?!?
public String buildHtml() {
StringBuffer sb = new StringBuffer();
sb.append(OPEN).append(HTML).append(CLOSE);
sb.append(OPEN).append(BODY).append(CLOSE);
...
sb.append(SLASH_OPEN).append(BODY).append(CLOSE);
sb.append(SLASH_OPEN).append(HTML).append(CLOSE);
return sb.toString();
}
}
接口的目的是定义合同而不提供实现。因此,您不能有静态方法,因为它们必须在接口中已经有一个实现,因为您不能重写静态方法。至于字段,只允许静态的
最终字段
,这些字段本质上是常量(在1.5+中,接口中也可以有枚举)。这些常量有助于定义没有幻数的接口
顺便说一句,没有必要为接口中的字段明确指定
static final
修饰符,因为只允许使用静态final字段。我将用我最喜欢的理论来解释这一点,即在这种情况下缺乏一致性是出于方便,而不是出于设计或必要,因为我没听过有说服力的论据说是这两个人中的任何一个
静态字段的存在(a)是因为它们在JDK1.0中存在,而在JDK1.0中做出了许多狡猾的决定,(b)接口中的静态最终字段是java当时最接近常量的东西
允许在接口中使用静态内部类,因为这是纯粹的语法糖——内部类实际上与父类无关
所以静态方法是不允许的,因为没有令人信服的理由这样做;一致性不足以改变现状
当然,在未来的JLS版本中,这是允许的,而不会破坏任何东西。实际上,有时有些人可以从静态方法中受益。它们可以用作实现接口的类的工厂方法。例如,这就是我们现在在openjdk中有Collection接口和Collections类的原因。因此,总是有一些变通方法-提供另一个具有私有构造函数的类,该构造函数将用作静态方法的“命名空间”。原因是,无论是否显式声明该修饰符,接口中定义的所有方法都是抽象的。抽象静态方法不是允许的修饰符组合,因为静态方法不能被重写 至于为什么接口允许静态字段。我有一种感觉,这应该被视为一种“特征”。我能想到的唯一可能性是对接口实现感兴趣的常量进行分组 我同意一致性是更好的方法。无统计
private final class HtmlConstants {
...
private HtmlConstants() { /* empty */ }
}
import static HtmlConstants.*;
public class HtmlBuilder { // no longer uses implements
...
}
public class InterfaceExample implements exp1 {
@Override
public void method() {
System.out.println("From method()");
}
public static void main(String[] args) {
new InterfaceExample().method2();
InterfaceExample.methodSta2(); // <--------------------------- would not compile
// methodSta1(); // <--------------------------- would not compile
exp1.methodSta1();
}
static void methodSta2() { // <-- it compile successfully but it can't be overridden in child classes
System.out.println("========= InterfaceExample :: from methodSta2() ======");
}
}
interface exp1 {
void method();
//protected void method1(); // <-- error
//private void method2(); // <-- error
//static void methodSta1(); // <-- error it require body in java 1.8
static void methodSta1() { // <-- it compile successfully but it can't be overridden in child classes
System.out.println("========= exp1:: from methodSta1() ======");
}
static void methodSta2() { // <-- it compile successfully but it can't be overridden in child classes
System.out.println("========= exp1:: from methodSta2() ======");
}
default void method2() { System.out.println("--- exp1:: from method2() ---");}
//synchronized default void method3() { System.out.println("---");} // <-- Illegal modifier for the interface method method3; only public, abstract, default, static
// and strictfp are permitted
//final default void method3() { System.out.println("---");} // <-- error
}