该主题充分说明了这一点-为什么不能在接口中声明静态方法的原因是什么?
public interface ITest {
public static String test();
}
上面的代码给了我以下错误(至少在Eclipse中):“接口方法ITest.test()的非法修饰符;仅允许public和abstract”。
该主题充分说明了这一点-为什么不能在接口中声明静态方法的原因是什么?
public interface ITest {
public static String test();
}
上面的代码给了我以下错误(至少在Eclipse中):“接口方法ITest.test()的非法修饰符;仅允许public和abstract”。
Answers:
这里有一些问题。第一个问题是声明一个静态方法而不定义它的问题。这是之间的区别
public interface Foo {
public static int bar();
}
和
public interface Foo {
public static int bar() {
...
}
}
出于Espo提到的原因,第一个是不可能的:您不知道哪个实现类是正确的定义。
Java 可以允许后者。实际上,从Java 8开始,它确实做到了!
static
方法interface
。方法必须是public
。
接口中不能使用静态方法的原因在于Java解析静态引用的方式。尝试执行静态方法时,Java不会费心寻找类的实例。这是因为静态方法不依赖于实例,因此可以直接从类文件中执行。假设接口中的所有方法都是抽象的,则VM必须寻找该接口的特定实现,以便找到静态方法后面的代码,以便可以执行该方法。然后,这与静态方法解析的工作方式矛盾,并且会在语言中引入不一致之处。
我将举例说明您的问题。假设我们有一个带有静态方法add的Math类。您将这样调用此方法:
Math.add(2, 3);
如果Math是接口而不是类,则它不能具有任何定义的函数。因此,说Math.add(2,3)之类的东西是没有道理的。
原因在于设计原则,即Java不允许多重继承。下例可以说明多重继承的问题:
public class A {
public method x() {...}
}
public class B {
public method x() {...}
}
public class C extends A, B { ... }
现在,如果您调用Cx()会发生什么?将执行Ax()还是Bx()?具有多重继承的每种语言都必须解决此问题。
接口在Java中允许某种受限的多重继承。为避免上述问题,不允许他们使用方法。如果我们在接口和静态方法上看同样的问题:
public interface A {
public static method x() {...}
}
public interface B {
public static method x() {...}
}
public class C implements A, B { ... }
同样的问题在这里,如果调用Cx()会发生什么?
A
包含int x(int z);
和接口B
包含相比,情况如何会更糟string x(int x);
?x(3)
接口C中的含义是什么?
静态方法不是实例方法。没有实例上下文,因此从接口实现它几乎没有意义。
现在,Java8允许我们甚至在接口中定义静态方法。
interface X {
static void foo() {
System.out.println("foo");
}
}
class Y implements X {
//...
}
public class Z {
public static void main(String[] args) {
X.foo();
// Y.foo(); // won't compile because foo() is a Static Method of X and not Y
}
}
注意:如果我们没有明确使用关键字default / static来使它们成为Default方法和Static方法,则默认情况下,Interface中的方法仍然是公共抽象的。
看来Java 8可能支持该接口中的静态方法,我的解决方案是在内部类中定义它们。
interface Foo {
// ...
class fn {
public static void func1(...) {
// ...
}
}
}
注释中也可以使用相同的技术:
public @interface Foo {
String value();
class fn {
public static String getValue(Object obj) {
Foo foo = obj.getClass().getAnnotation(Foo.class);
return foo == null ? null : foo.value();
}
}
}
内部类应该始终以Interface.fn...
而不是的形式进行访问Class.fn...
,这样就可以摆脱模棱两可的问题。
Java 8改变了世界,您可以在接口中使用静态方法,但是它迫使您为此提供实现。
public interface StaticMethodInterface {
public static int testStaticMethod() {
return 0;
}
/**
* Illegal combination of modifiers for the interface method
* testStaticMethod; only one of abstract, default, or static permitted
*
* @param i
* @return
*/
// public static abstract int testStaticMethod(float i);
default int testNonStaticMethod() {
return 1;
}
/**
* Without implementation.
*
* @param i
* @return
*/
int testNonStaticMethod(float i);
}
使用Java 8,接口现在可以具有静态方法。
例如,Comparator具有静态的naturalOrder()方法。
接口不能具有实现的要求也得到了放松。接口现在可以声明“默认”方法实现,这与常规实现类似,但有一个例外:如果您既继承自接口的默认实现又继承自超类的常规实现,则超类的实现将始终优先。
也许代码示例会有所帮助,我将使用C#,但是您应该可以继续学习。
假设我们有一个名为IPayable的接口
public interface IPayable
{
public Pay(double amount);
}
现在,我们有两个实现此接口的具体类:
public class BusinessAccount : IPayable
{
public void Pay(double amount)
{
//Logic
}
}
public class CustomerAccount : IPayable
{
public void Pay(double amount)
{
//Logic
}
}
现在,假设我们有多个帐户的集合,为此,我们将使用IPayable类型的通用列表
List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());
现在,我们要向所有这些帐户支付$ 50.00:
foreach (IPayable account in accountsToPay)
{
account.Pay(50.00);
}
因此,现在您将看到接口是多么有用。
它们仅用于实例化对象。不在静态类上。
如果您已使薪水保持静态,则在遍历IPayable的accountsToPay中时,将无法确定应在BusinessAcount还是CustomerAccount上调用薪水。