为啥我不能在接口中声明静态方法?
Posted
技术标签:
【中文标题】为啥我不能在接口中声明静态方法?【英文标题】:Why can't I declare static methods in an interface?为什么我不能在接口中声明静态方法? 【发布时间】:2010-09-06 12:21:15 【问题描述】:主题说得最多——静态方法不能在接口中声明的原因是什么?
public interface ITest
public static String test();
上面的代码给了我以下错误(至少在 Eclipse 中):“接口方法 ITest.test() 的非法修饰符;只允许公共和抽象”。
【问题讨论】:
请不要接受 Espo 的回答,因为它有缺陷。接口有一个类文件,可以包含静态方法的实现(如果 Java 设计者允许这样做),因此解析静态方法的实现没有问题。它与其他静态类完全一样。 我有点同意“erickson”***.com/questions/512877/…987654321@的回答 这将在 Java 8 中提供。 @Vadorequest GIYF 但无论如何,check here 官方文档链接:Java SE tutorial & Java Language Specification 9.2 【参考方案1】:这里有几个问题。第一个是声明静态方法而不定义它的问题。这就是区别
public interface Foo
public static int bar();
和
public interface Foo
public static int bar()
...
第一个是不可能的,因为Espo 提到的原因:你不知道哪个实现类是正确的定义。
Java 可以允许后者;事实上,从 Java 8 开始,它确实如此!
【讨论】:
是的 - 这是理想的而非技术性的。我想要它的原因是。可以在接口中具有静态“实现”方法,该方法仅引用接口中可以通过实现类轻松重用的其他“接口”方法。但是可以在接口中声明一个静态的类,这样就可以让这样的东西存在于其中,例如 MyInterface.Impl.doIt(MyInterface i, Object[] args) ... 从 Java 8 开始,您可以在interface
中定义 static
方法。方法必须是public
。
@OlivierGrégoire ...而且它们没有被继承,这是关键。
很好的答案,虽然“大约相当于”ROFLMAO xD 我会说它更像“有点像”。【参考方案2】:
接口中不能有静态方法的原因在于 Java 解析静态引用的方式。尝试执行静态方法时,Java 不会费心寻找类的实例。这是因为静态方法不依赖于实例,因此可以直接从类文件中执行。鉴于接口中的所有方法都是抽象的,VM 必须寻找接口的特定实现才能找到静态方法背后的代码,以便执行它。这与静态方法解析的工作方式相矛盾,并会在语言中引入不一致。
【讨论】:
这个解释不能解释问题。每个接口都有它自己的类文件,它可以包含静态方法。所以不需要查找特定的实现。 并非Java中的每个接口类型都在它自己的文件中,也不应该根据JLS。此外,JLS 并没有规定类必须始终存储在文件系统中,恰恰相反。 @Totophil:接口不能在单个 java 文件中,但编译后会有自己的类文件。这就是我写的。【参考方案3】:我会用一个例子来回答你的问题。假设我们有一个带有静态方法 add 的 Math 类。你可以这样调用这个方法:
Math.add(2, 3);
如果 Math 是一个接口而不是一个类,它就不能有任何定义的函数。因此,像 Math.add(2, 3) 这样的说法毫无意义。
【讨论】:
【参考方案4】:原因在于设计原则,即java不允许多重继承。多重继承的问题可以用下面的例子来说明:
public class A
public method x() ...
public class B
public method x() ...
public class C extends A, B ...
现在如果你调用 C.x() 会发生什么?将执行 A.x() 或 B.x() 吗?每种具有多重继承的语言都必须解决这个问题。
接口在 Java 中允许某种受限的多重继承。为了避免上述问题,他们不允许有方法。如果我们看一下接口和静态方法的相同问题:
public interface A
public static method x() ...
public interface B
public static method x() ...
public class C implements A, B ...
同样的问题,如果调用 C.x() 会发生什么?
【讨论】:
否决票的任何理由?一个解释性的评论会很好。 我不是反对者,但这不是对非静态方法也有效吗? 好的,这里有两种不同的可能性。可以实现或仅声明方法。我明白,必须实现静态方法。在这个意义上,我遇到了我的答案中提出的问题。如果你不这样做,你就会遇到 Espo 描述的问题——我不明白,因为我认为静态方法会被实现。你也不能因为这个原因声明一个静态抽象方法,试试看,编译器会报错。 好吧,忘记实现部分。问题是为什么我们不能宣布。是的,编译器会抱怨,为什么这是问题所在。我认为你没有回答。 如果接口A
包含int x(int z);
和接口B
包含string x(int x);
,情况会怎样?接口C中x(3)
是什么意思?【参考方案5】:
静态方法不是实例方法。没有实例上下文,因此从接口实现它没有什么意义。
【讨论】:
【参考方案6】:现在 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 将它们分别设为默认方法和静态方法,则接口中的方法默认仍然是公共抽象的。
【讨论】:
【参考方案7】:您的问题here 有一个非常简洁的答案。 (它以一种非常直接的方式解释它让我印象深刻,我想从这里链接它。)
【讨论】:
这不是问题的答案,充其量应该是评论。【参考方案8】:看来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...
的形式访问,这样就可以摆脱歧义问题。
【讨论】:
【参考方案9】:接口用于多态性,它适用于对象,而不是类型。因此(如前所述)拥有静态接口成员是没有意义的。
【讨论】:
在一些反思性的语境中似乎是有道理的【参考方案10】: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);
【讨论】:
【参考方案11】:修饰符的非法组合:静态和抽象
如果一个类的成员被声明为静态的,它可以与它的类名一起使用,该类名仅限于该类,而无需创建对象。
如果一个类的成员被声明为抽象,则需要将该类声明为抽象,并且需要在其继承的类(子类)中提供抽象成员的实现。
您需要为子类中的类的抽象成员提供一个实现,您将在其中更改静态方法的行为,也声明为抽象,仅限于基类,这是不正确的
【讨论】:
这如何回答这个问题?当你写关于类的时候,OP 询问了接口。【参考方案12】:由于静态方法不能被继承。所以把它放在界面中是没有用的。接口基本上是所有订阅者都必须遵守的契约。在接口中放置一个静态方法将强制订阅者实现它。现在这与静态方法不能被继承的事实相矛盾。
【讨论】:
静态方法总是被继承,但不能被覆盖。【参考方案13】:使用 Java 8,接口现在可以拥有静态方法。
例如,Comparator 有一个静态 naturalOrder() 方法。
接口不能有实现的要求也被放宽了。接口现在可以声明“默认”方法实现,这与普通实现类似,但有一个例外:如果您既从接口继承默认实现,又从超类继承普通实现,则超类的实现将始终具有优先权。
【讨论】:
天啊!我们有一个认真的程序员(和我,评论者)回答(和我,评论)10 年前的问题。 我没有注意到日期:) 哈哈!没问题!【参考方案14】:也许一个代码示例会有所帮助,我将使用 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);
所以现在你看到了接口是如何非常有用的。
它们仅用于实例化对象。不在静态类上。
如果您已将 pay 设为静态,则当循环通过 accountsToPay 中的 IPayable 时,将无法确定它是否应该在 BusinessAcount 或 CustomerAccount 上调用 pay。
【讨论】:
仅仅因为静态方法在这个例子中没有意义,并不意味着它们在任何例子中都没有意义。在您的示例中,如果 IPayable 接口具有静态方法“IncrementPayables”来跟踪添加了多少应付账款,这将是一个真实的用例。当然,总是可以使用抽象类,但这不是您要解决的问题。您的示例本身不会破坏接口中的静态方法。以上是关于为啥我不能在接口中声明静态方法?的主要内容,如果未能解决你的问题,请参考以下文章