主题说明了其中的大部分——静态方法不能在接口中声明这一事实的原因是什么?
public interface ITest {
public static String test();
}
上面的代码给出了以下错误(至少在Eclipse中):"接口方法itest.test()的非法修饰符;只允许使用public&abstract"。
请不要接受ESPO的回答,因为它有缺陷。接口有一个类文件,它可以包含静态方法的实现(如果Java设计器允许的话),因此在解决静态方法的实现方面没有问题。它与其他静态类的工作方式完全相同。
我同意"erickson"stackoverflow.com/questions/512877/&hellip给出的答案。
这将在Java 8 BTW中可用。
@m0skit0你有关于这个的链接吗?听起来很酷。
@但无论如何,请在这里检查
是的,我当然可以找到它;)但是当你这样说的时候,最好给出链接!谢谢。
官方文档链接:Java SE教程和Java语言规范9.2
这里有几个问题要讨论。第一个问题是声明一个静态方法而不定义它。这就是
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以来,您可以在EDCOX1 1中定义EDCOX1 0个方法。方法必须是public。
@Oliviergr&233;Goire……它们不是继承的,这是关键。
很好的答案,虽然"近似等效"的roflmao xd,我会说它更像"有点相似"。
在接口中不能使用静态方法的原因在于Java解析静态引用的方式。当尝试执行静态方法时,Java不会麻烦寻找类的实例。这是因为静态方法不依赖实例,因此可以直接从类文件执行。考虑到接口中的所有方法都是抽象的,虚拟机必须查找接口的特定实现,以便找到静态方法背后的代码,以便执行该方法。这就与静态方法解析的工作原理相矛盾,并将在语言中引入不一致性。
这个解释不能解释这个问题。每个接口都有自己的类文件,它可以包含静态方法。因此,不需要查找特定的实现。
不是Java中的每个接口类型都在它自己的文件中,也不应该根据JLS。另外,JLS并没有规定类必须始终存储在文件系统中,恰恰相反。
@ totOfiel:接口不能在一个Java文件中,但编译后会有自己的类文件。我就是这么写的。
我举个例子回答你的问题。假设我们有一个带有静态方法add的数学类。您可以这样调用此方法:
Math.add(2, 3);
如果Math是接口而不是类,则它不能有任何已定义的函数。因此,说一些类似数学的话。加(2,3)是没有意义的。
其原因在于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)的含义是什么?
我不确定我是否同意确切的措辞,但在解释为什么不允许使用接口中的静态方法时,答案确实有意义。
但允许静态字段。我可以在您的接口上定义一个A.x和一个B.x。在这种情况下,试图引用(不明确的)C.x会导致编译时错误。不能对静态方法做同样的事情吗?(这是Java 8中的计划吗?)
静态方法不是实例方法。没有实例上下文,因此从接口实现它没有什么意义。
现在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使它们成为默认方法和静态方法resp,那么默认情况下,接口中的方法仍然是公共抽象的。
你的问题有一个非常好和简洁的答案。(我觉得这是一种非常直接的解释方式,我想从这里把它联系起来。)
这不是问题的答案,最好是一个评论。
在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);
}
With Java 8, interfaces can now have static methods.
例如,Comparator有一个静态的naturalOrder()方法。
接口不能实现的要求也得到了放宽。接口现在可以声明"默认"方法实现,这与普通实现类似,但有一个例外:如果从接口继承默认实现,从超类继承普通实现,则超类的实现将始终优先。
天啊!我们有一个严肃的程序员(和我,评论者)回答(和我,评论)10年前的问题。
我没注意到日期:)
哈哈!没问题!
因为静态方法不能被继承。所以把它放在接口中没用。接口基本上是所有订户都必须遵守的合同。在接口中放置静态方法将强制订阅服务器实现它。这与静态方法不能被继承的事实相矛盾。
静态方法总是继承的,但不能重写。
修饰符非法组合:静态和抽象
如果一个类的成员被声明为静态的,那么它可以与限制在该类中的类名一起使用,而不创建对象。
如果某个类的成员声明为抽象的,则需要将该类声明为抽象的,并且需要在继承的类(子类)中提供该抽象成员的实现。
您需要为要更改静态方法行为的子类中的类的抽象成员提供一个实现,该静态方法的行为也被声明为抽象,该抽象仅限于基类,这是不正确的
这是如何回答这个问题的?当你写关于类的文章时,OP询问了关于接口的问题。
也许一个代码示例会有所帮助,我将使用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 accountsToPay = new List();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());
现在,我们要向所有这些账户支付50美元:
foreach (IPayable account in accountsToPay)
{
account.Pay(50.00);
}
所以现在您看到了接口是如何非常有用的。
它们仅用于实例化对象。不在静态类上。
如果您将Pay设置为静态,则在通过iPayable的In AccountStopay循环时,将无法确定它是否应调用BusinessAccount或CustomerAccount上的Pay。
-1所以为什么在接口中允许静态字段。
仅仅因为静态方法在本例中没有意义,并不意味着它们在任何示例中都没有意义。在您的示例中,如果ipayable接口具有跟踪添加了多少应付款的静态方法"incrementpayables",那么这将是一个实际的用例。当然,可以使用抽象类,但这不是您要解决的问题。您的示例本身不会破坏接口中的静态方法。