ChatGPT解决这个技术问题 Extra ChatGPT

为什么Java中的静态方法不能是抽象的?

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

abstract class foo {
    abstract void bar( ); // <-- this is ok
    abstract static void bar2(); //<-- this isn't why?
}
几个原因:静态方法必须有一个主体,即使它们是抽象类的一部分,因为不需要创建类的实例来访问其静态方法。另一种思考方式是,如果我们暂时假设它是允许的,那么问题是静态方法调用不提供任何运行时类型信息 (RTTI),请记住不需要创建实例,因此它们无法重定向对其特定的覆盖实现,因此允许抽象静态完全没有意义。换句话说,它不能提供任何多态性好处,因此是不允许的。

u
user207421

因为“抽象”的意思是:“不实现任何功能”,而“静态”的意思是:“即使没有对象实例也有功能”。这是一个逻辑矛盾。


更简洁的答案是“糟糕的语言设计”。静态应该意味着“属于该类”,因为正如这个问题所展示的那样,这就是它的直观使用方式。请参阅 Python 中的“类方法”。
@Tomalak我很抱歉,我不清楚。当然,静态方法“属于类”。尽管如此,它只是在它存在于同一个命名空间中的意义上。静态方法不是类对象本身的方法:它不以 'this' 作为类对象进行操作,也没有正确参与继承链。如果它真的是一个类方法 abstract static 将非常有意义。这将是子类对象必须实现的类对象本身的方法。当然,尽管我对语言感到不满,但您的回答是正确的。
这不是逻辑矛盾,而是语言缺陷,其他多种语言都支持这一概念。 “抽象”是指“在子类中实现”,“静态”是指“在类而不是类实例上执行”,没有逻辑上的矛盾。
@Eric:仍然,你所说的不适用于abstract static:“在子类中实现”的函数 X不能同时被“执行”在类上”- 仅在 子类 上。那时它不再是抽象的了。
@Tomakak:您的逻辑是循环的。 static 并不意味着“非空”——这只是 Java 不允许静态方法抽象的结果。它的意思是“可在课堂上调用”。 (这应该意味着“在类上可调用 only”,但这是另一个问题。)如果 Java 支持 abstract static 方法,我希望它意味着方法 1) 必须由子类实现,并且2) 是子类的类方法。有些方法作为实例方法没有意义。不幸的是,Java 不允许您在创建抽象基类(或接口)时指定这一点。
佚名

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


Java 充满了奇怪的限制。仅访问最终变量的闭包是另一种情况。剩下的名单几乎是无穷无尽的。了解它们及其变通方法是 Java 程序员的工作。为了玩得开心,我们必须在业余时间使用比 Java 更好的东西。但我不会打扰。那是取得进步的种子。
我相信你所说的“糟糕的语言设计”实际上更像是一种“保护性语言设计”,其目的是限制程序员由于不必要的语言特性而违反 OO 原则。
“抽象静态”的概念是否违反了OO原则?
@threed,一点也不,但当然有些人说 static 本身的概念本身就已经违反了....
对静态的需求清楚地表明“OO 原则”并不像通常声称的那样包罗万象。
G
GaryF

您不能覆盖静态方法,因此使其抽象化将毫无意义。此外,抽象类中的静态方法属于该类,而不是覆盖类,因此无论如何都不能使用。


是的,静态方法不能在 Java 中被覆盖,这确实是一种耻辱。
@Michel:重点是什么?如果您想要基于实例的行为,请使用实例方法。
这个答案是不正确的。抽象类中的静态方法工作正常并且很常用。只是类本身的静态方法可能不是抽象的。 @Michel 重写静态方法没有意义。如果没有实例,运行时如何知道调用哪个方法?
@erickson - 即使没有实例,类层次结构也是完整的 - 静态方法的继承可以像实例方法的继承一样工作。 Smalltalk 做到了,而且非常有用。
@matiasg 这根本不是什么新鲜事。抽象类总是被允许有静态的、非抽象的方法。
J
Jared

方法的 abstract 注释指示必须在子类中覆盖该方法。

在 Java 中,static 成员(方法或字段)不能被子类覆盖(在其他面向对象的语言中不一定如此,请参阅 SmallTalk。)static 成员可能隐藏,但这与覆盖有着根本的不同。

由于无法在子类中覆盖静态成员,因此无法将 abstract 注释应用于它们。

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

ClassA.methodA();

methodA();

在 SmallTalk 中,类名不是可选的,所以语法是(注意 SmallTalk 不使用 . 来分隔“主语”和“动词”,而是使用它作为语句终止符):

ClassA methodA.

因为总是需要类名,所以总是可以通过遍历类层次结构来确定方法的正确“版本”。对于它的价值,我偶尔会错过 static 继承,并且在我刚开始使用它时被 Java 中缺乏静态继承所困扰。此外,SmallTalk 是鸭子类型的(因此不支持按合同编程。)因此,它没有用于类成员的 abstract 修饰符。


“静态成员不能被子类覆盖”是错误的。至少在 Java6 中是可能的。不知道从什么时候开始。
@Steven De Groote 静态成员确实不能被子类覆盖。如果子类具有与超类中的静态方法具有相同签名的静态方法,它不会覆盖它,而是隐藏它。 http://docs.oracle.com/javase/tutorial/java/IandI/override.html 不同之处在于多态性仅适用于被覆盖的方法,而不适用于隐藏的方法。
@John29 感谢您的澄清,但除了命名差异之外,它的用法似乎相似。
@Steven De Groote 是的,用法相似,但行为不同。这就是为什么没有静态抽象方法的原因——如果静态抽象方法不支持多态,那么它们的意义何在?
@Steven De Groote:当您在超类本身中调用该方法时,差异变得明显。假设 Super.foo 调用 Super.bar。如果子类实现了 Subclass.bar,然后调用 foo,那么 foo 仍然会调用 Super.bar,而不是 Subclass.bar。因此,您真正拥有的是两种完全不同且不相关的方法,都称为“bar”。这在任何有用的意义上都不是压倒一切的。
a
anshulkatta

我也问了同样的问题,这是为什么

由于抽象类说,它不会给出实现并允许子类给出它

所以 Subclass 必须覆盖 Superclass 的方法,

规则 1 - 不能覆盖静态方法

因为静态成员和方法是编译时元素,这就是为什么允许静态方法的重载(编译时多态性)而不是覆盖(运行时多态性)

所以,它们不能是抽象的。

没有抽象静态之类的东西 <--- Java Universe 中不允许


-1,“Java 不允许重写静态方法,因为静态成员和方法是编译时元素”是不正确的。使用 abstract static 肯定可以进行静态类型检查,请参阅 stackoverflow.com/questions/370962/…。 Java 不允许覆盖静态方法的真正原因是因为 Java 不允许覆盖静态方法。
重载与多态无关。除了前缀“over”之外,重载和覆盖没有任何共同之处,就像 Java 和 JavaScript 恰好都有“Java”一样。方法的名称不是它的身份,而是它的签名。所以 foo(String)foo(Integer) 不同——仅此而已。
@CaptainMan 重载字面上称为“参数多态性”,因为根据参数的类型,会调用不同的方法,即多态性。
m
mjs

这是一种糟糕的语言设计,实际上没有理由说明为什么它不可能。

事实上,这里有一种模式或方式,说明如何在 **Java ** 中模仿它,让您至少能够修改自己的实现:

public static abstract class Request {                 

        // Static method
        public static void doSomething() {
                get().doSomethingImpl();
        }
        
        // Abstract method
        abstract void doSomethingImpl();

        /////////////////////////////////////////////
        private static Request SINGLETON;
        private static Request get() {
            if ( SINGLETON == null ) {
                // If set(request) is never called prior,
                // it will use a default implementation. 
                return SINGLETON = new RequestImplementationDefault();
            }
            return SINGLETON;
        }
        public static Request set(Request instance){
            return SINGLETON = instance;
        }
        /////////////////////////////////////////////
}

两种实现:

/////////////////////////////////////////////////////

public static final class RequestImplementationDefault extends Request {
        @Override void doSomethingImpl() {
                System.out.println("I am doing something AAA");
        }
}

/////////////////////////////////////////////////////

public static final class RequestImplementaionTest extends Request {
        @Override void doSomethingImpl() {
                System.out.println("I am doing something BBB");
        }
}

/////////////////////////////////////////////////////

可以如下使用:

Request.set(new RequestImplementationDefault());

// Or

Request.set(new RequestImplementationTest());

// Later in the application you might use

Request.doSomething();

这将允许您静态调用您的方法,但能够更改测试环境的实现。

从理论上讲,您也可以在 ThreadLocal 上执行此操作,并且能够为每个 Thread 上下文设置实例,而不是在这里看到的完全全局,然后可以执行 Request.withRequest(anotherRequestImpl, () -> { ... }) 或类似操作。

现实世界通常不需要 ThreadLocal 方法,并且通常能够在全局范围内更改 测试环境 的实现就足够了。

请注意,这样做的唯一目的是使一种方法能够保留直接、轻松和干净地调用静态方法提供的方法的能力,同时能够在以稍微更复杂为代价的情况下切换实现执行。

这只是一种解决通常不可修改的静态代码的模式。


我不明白您在哪里提供了问题中提出的 abstract static 方法示例,并且您用粗体写了 CAN BE DONE IN JAVA。这完全是误导。
它本身不允许您将其定义为抽象静态,但您可以获得类似的结果,您可以使用此模式/hack 更改 s 静态方法的实现。这几乎不会被误导。可以做到,但使用不同的语义。
这是一个扩展抽象类,然后将静态方法放入子类的示例。无论如何,这不是可以在 JAVA 中完成的示例。
@ScubaSteve首先,您的结论是错误的。其次,它达到了相同的结果。这意味着对类的静态访问可以由另一个实现更改。说我使 static 关键字可抽象并不是一个答案,但是使用这种模式,您可以使用静态方法并仍然更改它们的实现。虽然它确实具有全局性的负面影响,但对于测试/生产/开发环境,它对我们有用。
R
Rahul Saxena

定义抽象方法只是为了在子类中重写它。但是,静态方法不能被覆盖。因此,具有抽象的静态方法是编译时错误。现在下一个问题是为什么不能覆盖静态方法?

这是因为静态方法属于一个特定的类而不是它的实例。如果您尝试覆盖静态方法,您将不会收到任何编译或运行时错误,但编译器只会隐藏超类的静态方法。


A
AndreyS Scherbakov

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

据此,抽象静态方法将毫无用处,因为您永远不会将其引用替换为某个已定义的主体。


m
mhp

我看到已经有无数的答案,但我没有看到任何实际的解决方案。当然,这是一个真正的问题,没有充分的理由在 Java 中排除这种语法。由于原始问题缺少可能需要的上下文,因此我提供了上下文和解决方案:

假设您在一堆相同的类中有一个静态方法。这些方法调用特定于类的静态方法:

class C1 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C1
    }
}
class C2 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C2
    }
}

C1C2 中的 doWork() 方法是相同的。可能有很多这样的类:C3 C4 等。如果允许 static abstract,您可以通过执行以下操作来消除重复代码:

abstract class C {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }

    static abstract void doMoreWork(int k);
}

class C1 extends C {
    private static void doMoreWork(int k) {
        // code for class C1
    }
}

class C2 extends C {
    private static void doMoreWork(int k) {
        // code for class C2
    }
}

但这不会编译,因为 static abstract 组合是不允许的。但是,这可以通过 static class 构造来规避,这是允许的:

abstract class C {
    void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    abstract void doMoreWork(int k);
}
class C1 {
    private static final C c = new  C(){  
        @Override void doMoreWork(int k) {
            System.out.println("code for C1");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}
class C2 {
    private static final C c = new C() {
        @Override void doMoreWork(int k) {
            System.out.println("code for C2");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}

使用此解决方案,唯一重复的代码是

    public static void doWork() {
        c.doWork();
    }

由于在您的最终解决方案中,抽象类 C 没有任何静态方法,那么为什么不让 C1 和 C2 扩展它并覆盖 doMoreWork() 方法并让任何其他类创建它的实例并调用所需的方法。基本上你正在做同样的事情,即使用匿名类扩展类 C,然后在 C1 和 C2 中使用它的静态实例来允许从静态方法中进行访问,但这根本不是必需的。
我不明白您在此处提供的上下文。在您的最终解决方案中,您可以调用 C1.doWork()C2.doWork() 但您不能调用 C.doWork()。同样在您提供的示例中,它不起作用,假设如果它被允许,那么类 C 将如何找到 doMoreWork() 的实现?最后,我将您的上下文代码称为糟糕的设计。为什么?仅仅是因为您为唯一的代码创建了一个单独的函数,而不是为常见的代码创建一个函数,然后在类 C 中实现一个静态函数。这更容易!!!
h
hyper-neutrino

假设有两个类,ParentChildParentabstract。声明如下:

abstract class Parent {
    abstract void run();
}

class Child extends Parent {
    void run() {}
}

这意味着 Parent 的任何实例都必须指定 run() 的执行方式。

但是,现在假设 Parent 不是 abstract

class Parent {
    static void run() {}
}

这意味着 Parent.run() 将执行静态方法。

abstract 方法的定义是“已声明但未实现的方法”,这意味着它本身不返回任何内容。

static 方法的定义是“无论在哪个实例上调用它,都为相同参数返回相同值的方法”。

abstract 方法的返回值会随着实例的变化而变化。 static 方法不会。 static abstract 方法几乎是一种返回值恒定但不返回任何内容的方法。这是一个逻辑矛盾。

此外,static abstract 方法确实没有太多理由。


S
Sunil Kumar Jha

抽象类不能有静态方法,因为抽象是为了实现动态绑定而静态方法静态绑定到它们的功能。静态方法意味着行为不依赖于实例变量,因此不需要实例/对象。只需要类。静态方法属于类而不是对象。它们存储在称为PERMGEN 的内存区域中,从该区域与每个对象共享。抽象类中的方法动态绑定到它们的功能。


抽象类当然可以有静态方法。但不是静态抽象方法。
然后请Java添加一个新关键字,用于属于类而不是实例的动态绑定方法。
p
pushkin

将方法声明为 static 意味着我们可以通过其类名调用该方法,如果该类也是 abstract,则调用它是没有意义的,因为它不包含任何主体,因此我们不能声明方法staticabstract


但是我们希望在扩展类中有静态方法。例如,写一个类的名称而不是 getSimpleName()。我们希望拥有 abstract static String getClassName(); 并在所有子类中扩展它。
S
Swapnillc

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


M
Mnementh

可以在没有类实例的情况下调用静态方法。在您的示例中,您可以调用 foo.bar2(),但不能调用 foo.bar(),因为对于 bar,您需要一个实例。以下代码将起作用:

foo var = new ImplementsFoo();
var.bar();

如果您调用静态方法,它将始终执行相同的代码。在上面的例子中,即使你在 ImplementsFoo 中重新定义了 bar2,对 var.bar2() 的调用也会执行 foo.bar2()。

如果 bar2 现在没有实现(这就是抽象的意思),您可以调用没有实现的方法。这是非常有害的。


并且可以在没有实例的情况下调用抽象静态方法,但需要在子类中创建实现。这不完全是多态性,但解决它的唯一方法是让具体的孩子实现一个“需要”“抽象静态”方法的接口。凌乱,但可行。
其实,我错了。接口中也不能有静态方法。语言缺陷。
C
Community

我相信我已经找到了这个问题的答案,即为什么接口的方法(像父类中的抽象方法一样工作)不能是静态的。 Here is the full answer (not mine)

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

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

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

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

那么任何 Foo.bar(); 调用显然都是非法的,您将始终使用 Foo2.bar();

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

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

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


P
Pradeep

因为抽象类是一个面向对象的概念,而静态成员不是面向对象的一部分......现在我们可以在接口中声明静态完整方法,我们可以通过在接口中声明主方法来执行接口

interface Demo 
{
  public static void main(String [] args) {
     System.out.println("I am from interface");
  }
}

s
sbgib

因为抽象方法总是需要通过子类来实现。但是如果你将任何方法设为静态,则此方法无法覆盖

例子

abstract class foo {
    abstract static void bar2(); 
}


class Bar extends foo {
    //in this if you override foo class static method then it will give error
}

O
Olaf Leimann

拥有一个抽象静态方法的想法是你不能直接为那个方法使用那个特定的抽象类,但是只有一阶导数才能实现那个静态方法(或者对于泛型:你的泛型的实际类利用)。

这样,您可以创建一个 sortableObject 抽象类,甚至可以创建与(自动)抽象静态方法的接口,这些方法定义了排序选项的参数:

public interface SortableObject {
    public [abstract] static String [] getSortableTypes();
    public String getSortableValueByType(String type);
}

现在您可以定义一个可排序对象,该对象可以按所有这些对象相同的主要类型进行排序:

public class MyDataObject implements SortableObject {
    final static String [] SORT_TYPES = {
        "Name","Date of Birth"
    }
    static long newDataIndex = 0L ;

    String fullName ;
    String sortableDate ;
    long dataIndex = -1L ;
    public MyDataObject(String name, int year, int month, int day) {
        if(name == null || name.length() == 0) throw new IllegalArgumentException("Null/empty name not allowed.");
        if(!validateDate(year,month,day)) throw new IllegalArgumentException("Date parameters do not compose a legal date.");
        this.fullName = name ;
        this.sortableDate = MyUtils.createSortableDate(year,month,day);
        this.dataIndex = MyDataObject.newDataIndex++ ;
    }
    public String toString() {
        return ""+this.dataIndex+". "this.fullName+" ("+this.sortableDate+")";
    }

    // override SortableObject 
    public static String [] getSortableTypes() { return SORT_TYPES ; }
    public String getSortableValueByType(String type) {
        int index = MyUtils.getStringArrayIndex(SORT_TYPES, type);
        switch(index) {
             case 0: return this.name ;
             case 1: return this.sortableDate ;
        }
        return toString(); // in the order they were created when compared
    }
}

现在您可以创建一个

public class SortableList<T extends SortableObject> 

that can retrieve the types, build a pop-up menu to select a type to sort on and resort the list by getting the data from that type, as well as hainv an add function that, when a sort type has been selected, can auto -sort new items in。注意SortableList的实例可以直接访问“T”的静态方法:

String [] MenuItems = T.getSortableTypes();

必须使用实例的问题是 SortableList 可能还没有项目,但已经需要提供首选排序。

切里奥,奥拉夫。


b
bruhhhhh

首先,关于抽象类的一个关键点——抽象类不能被实例化(参见wiki)。因此,您不能创建抽象类的 any 实例。

现在,java 处理静态方法的方式是与该类的所有实例共享该方法。

所以,如果你不能实例化一个类,那么这个类就不能有抽象的静态方法,因为抽象方法需要被扩展。

繁荣。


抽象类中的每个方法都需要对其类进行扩展才能执行,所以这不是借口。您可以扩展抽象类(同时实现抽象方法)。所以这不能作为解释。
a
akhil_mittal

根据 Java doc

静态方法是与定义它的类相关联的方法,而不是与任何对象相关联的方法。类的每个实例共享其静态方法

在 Java 8 中,除了默认方法之外,接口中还允许使用静态方法。这使我们更容易在我们的库中组织辅助方法。我们可以将特定于接口的静态方法保留在同一个接口中,而不是在单独的类中。

一个很好的例子是:

list.sort(ordering);

代替

Collections.sort(list, ordering);

doc 本身也给出了使用静态方法的另一个示例:

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

P
Praveen Kumar

因为“抽象”意味着该方法将被覆盖,并且不能覆盖“静态”方法。


这个答案没有增加之前的答案尚未解决的任何内容。
@MarsAtomic 我认为这比投票最多的答案更合适。此外,它很简洁。
然后,当您有足够的代表时,您可以编辑较早的答案以改进它们。您所做的只是通过创建重复的答案给信号添加噪音。请遵循 Stack Overflow 的既定规则和习惯,而不是创建自己的规则和习惯并期望其他人都遵循。
我不同意,请将我的答案与其他答案进行比较,尤其是投票最多的答案。
“为什么我不能这样做?”答案:“因为你不能”。
D
Darshan Chaudhary

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

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


A
Ashish Ranjan

因为 abstract 是应用于抽象方法的关键字,所以不指定主体。如果我们谈论静态关键字,它属于类区域。


请详细说明您的答案。
M
Manu

因为如果您在类中使用任何静态成员或静态变量,它将在类加载时加载。


为什么这会是一个问题?
M
Michael Scarpace

有一种情况是 static 和 abstract 可以一起使用,即这两个修饰符都放在嵌套类的前面。


P
PAVAN SAI POTNURU

静态方法 无需创建类的实例即可调用静态方法。静态方法属于类而不属于类的对象。静态方法可以访问静态数据成员,也可以更改它的值。 Abstract Keyword 用于实现抽象。不能在子类中覆盖或实现静态方法。因此,将静态方法设为抽象是没有用的。


就在这里。想象一下,您有一个响应处理器。您定义 ResponseA、ResponseB、ResponseC。每个响应类型作为关联的构建器(内部类),要获得它,您有一个静态方法“builder()”。 Processor读取数据,需要使用其中一个Builder来获取Response的实例。因此,在 Response 中,您希望强制 Response 的每个子类都有一个方法 builder()。所以 builder() 必须是抽象的,理想情况下也应该是静态的。但在 Java 中这是不可能的。另一个例子:抽象类 Shape,具有抽象的静态布尔 hasCorners() 方法。
L
Lucas de Lima

在一行中,这种危险的组合(抽象+静态)违反了面向对象的原则,即多态性。

在继承情况下,JVM 将在运行时由实现决定实例的类型(运行时多态性)而不是引用变量的类型(编译时多态性)。

使用@Overriding:

https://i.stack.imgur.com/D1leI.png

静态方法不支持@overriding(运行时多态),而只支持方法隐藏(编译时多态)。

使用@Hiding:

https://i.stack.imgur.com/UaF85.png

但是在抽象静态方法的情况下,父(抽象)类没有该方法的实现。因此,子类型引用是唯一可用的,它不是多态性。

子参考是唯一可用的:

https://i.stack.imgur.com/3Am2z.png

出于这个原因(抑制 OOP 特性),Java 语言将抽象 + 静态视为方法的非法(危险)组合。


假设您有一个 Shape 和子类 Circle 和 Square。为什么我们不能在 Shape 上定义一个抽象的静态 hasCorners()?您需要一个工具虚拟实例来调用 hasCorners(),这很糟糕,因为您不能执行 Circle.hasCorners() 或 Square.hasCorners()。
M
Maralc

您可以使用 Java 8 中的接口来执行此操作。

这是关于它的官方文档:

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html


如何?我一直在寻找解决方案,但找不到任何解决方案。
呜?你不能。所有静态接口方法都必须使用接口类调用。
这个答案是错误的,并且会误导 Java 新手。这确实显示了抽象静态方法的任何示例,因为它无法在其他答案中实现和说明
f
frostman

因为如果一个类扩展了一个抽象类,那么它必须重写抽象方法,这是强制性的。并且由于静态方法是在编译时解析的类方法,而重写方法是在运行时解析并遵循动态多态性的实例方法。


请大写和标点这个混乱。