问题是,在Java中为什么不能定义抽象静态方法?例如

abstract class foo {
    abstract void bar( ); // <-- this is ok
    abstract static void bar2(); //<-- this isn't why?
}

当前回答

因为抽象方法属于类,不能被实现类覆盖。即使存在具有相同签名的静态方法,它也会隐藏该方法,而不会覆盖它。 因此,将抽象方法声明为静态方法是无关紧要的,因为它永远不会获得对象体。因此,编译时错误。

其他回答

糟糕的语言设计。直接调用静态抽象方法要比为使用该抽象方法而创建实例有效得多。当使用抽象类作为枚举无法扩展的变通方法时尤其如此,这是另一个糟糕的设计示例。希望他们能在下一个版本中解决这些限制。

根据定义,静态方法不需要知道这些。因此,它不能是一个虚方法(根据通过this获得的动态子类信息重载);相反,静态方法重载仅基于编译时可用的信息(这意味着:一旦引用了父类的静态方法,就调用父类方法,而不调用子类方法)。

根据这一点,抽象静态方法将是非常无用的,因为您永远不会用一些已定义的对象来代替它的引用。

我相信我已经找到了这个问题的答案,即为什么接口的方法(就像父类中的抽象方法一样工作)不能是静态的。以下是完整的答案(不是我的)

基本上静态方法可以在编译时绑定,因为要调用它们你需要指定一个类。这与实例方法不同,对于实例方法,在编译时调用方法的引用的类可能是未知的(因此只能在运行时确定调用哪个代码块)。

如果您正在调用一个静态方法,那么您已经知道实现它的类,或者它的任何直接子类。如果你定义

abstract class Foo {
    abstract static void bar();
}

class Foo2 {
    @Override
    static void bar() {}
}

然后任意Foo.bar();调用显然是非法的,您将始终使用Foo2.bar();。

考虑到这一点,静态抽象方法的唯一目的是强制子类实现这样的方法。你可能最初认为这是非常错误的,但如果你有一个泛型类型参数<E扩展MySuperClass>,它将很好地通过接口保证E可以. dosomething()。请记住,由于类型擦除,泛型只存在于编译时。

那么,它有用吗?是的,也许这就是为什么Java 8允许在接口中使用静态方法(尽管只有默认实现)。为什么不在类中使用默认实现抽象静态方法呢?很简单,因为具有默认实现的抽象方法实际上是一个具体方法。

为什么不使用没有默认实现的抽象/接口静态方法?显然,这仅仅是因为Java识别它必须执行哪个代码块的方式(我回答的第一部分)。

方法的抽象注释表明该方法必须在子类中重写。

在Java中,静态成员(方法或字段)不能被子类覆盖(在其他面向对象语言中不一定是这样,请参阅SmallTalk)。静态成员可能被隐藏,但这与被覆盖有本质区别。

由于静态成员不能在子类中被重写,因此抽象注释不能应用于它们。

顺便说一句,其他语言确实支持静态继承,就像实例继承一样。从语法的角度来看,这些语言通常要求在语句中包含类名。例如,在Java中,假设你在ClassA中编写代码,这是等价的语句(如果methodA()是一个静态方法,并且没有具有相同签名的实例方法):

ClassA.methodA();

and

methodA();

在SmallTalk中,类名不是可选的,所以语法是(注意,SmallTalk不使用。将“主语”和“动词”分开,而是将其用作语句结束符):

ClassA methodA.

因为总是需要类名,所以总是可以通过遍历类层次结构来确定方法的正确“版本”。无论如何,我偶尔会错过静态继承,当我第一次开始使用Java时,我就被Java中缺乏静态继承所困扰。此外,SmallTalk是duck类型的(因此不支持契约式编程)。因此,类成员没有抽象修饰符。

当常规方法要被子类覆盖并提供功能时,它们可以是抽象的。 假设类Foo由Bar1, Bar2, Bar3等扩展。因此,每个人都将根据自己的需要拥有自己的抽象类版本。

静态方法根据定义属于类,它们与类的对象或类的子类的对象无关。它们甚至不需要它们存在,它们可以在不实例化类的情况下使用。因此,它们需要准备就绪,不能依赖于子类向它们添加功能。