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


592

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

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

9
出于几个原因:即使静态方法是抽象类的一部分,静态方法也必须具有主体,因为不需要创建类的实例来访问其静态方法。考虑它的另一种方法是,如果我们暂时假设它是允许的,那么问题是静态方法调用不提供任何运行时类型信息(RTTI),请记住不需要创建实例,因此它们无法重定向它们特定的重写实现,因此允许绝对静态完全没有意义。换句话说,它不能提供任何多态性好处,因此是不允许的。
sactiw

6
如果您有什么要回答的问题,请将其作为回答而不是发表评论
Solomon Ucko

Answers:


569

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


353
更为简洁的答案是“语言设计不良”。静态应该表示“属于该类”,因为正如这个问题所说明的,这就是直观地使用它的方式。请参见Python中的“类方法”。
亚历山大·隆伯格

12
@Tomalak我很抱歉,我不清楚。当然,静态方法“属于该类”。不过,仅从某种意义上说,它位于相同的名称空间中。静态方法不是类对象本身的方法:它不能以“ this”作为类对象,并且不能正确地参与继承链。如果确实是一个类方法,那abstract static将是很有意义的。这是子类对象必须实现的类对象本身的方法。当然,尽管我对语言一无所知,但事情的立场是正确的。
亚历山大·隆伯格

693
这不是逻辑上的矛盾,这是一种语言缺陷,其他多种语言也支持此概念。“抽象”表示“在子类中实现”,“静态”表示“在类上执行,而不是在类实例上执行”,这没有逻辑上的矛盾。
Eric Grange 2010年

10
@Eric:而且,您所说的内容仍然不适用于abstract static:“在子类中实现”的函数X 不能 同时在“类上”执行-只能在子类上执行。然后它不再是抽象的了。
Tomalak 2010年

72
@Tomakak:你的逻辑是循环的。static并不意味着“不为空”-这只是Java不允许将静态方法抽象化的结果。它的意思是“可上课”。(这应该意味着“ 只能在该类上调用”,但这是另一个问题。)如果Java支持的abstract static方法,我希望它的意思是方法1)必须由子类实现,而2)是子类的类方法。有些方法只是没有实例方法的意义。不幸的是,Java在创建抽象基类(或接口)时不允许您指定。
迈克尔·卡曼

326

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


25
Java充满了奇怪的局限性。闭包仅访问最终变量是另一个。剩下的名单几乎是无止境的。了解它们及其变通办法是Java程序员的工作。为了获得乐趣,我们必须在业余时间使用比Java更好的东西。但是我不会理会。那是取得进展的种子。
ceving 2012年

22
我相信您所说的“语言设计不良”实际上更多是“保护性语言设计”,其目的是限制程序员由于不必要的语言功能而违反OO原则。
ethanfar 2014年

22
“抽象静态”的概念是否违反OO原则?
特雷弗

7
@threed,不是所有,但当然也有乡亲说,谁的仅仅是一个概念static本身已经是违反了....
Pacerier

4
对静态的需求清楚地表明,“ OO原则”并不像通常要求的那样包罗万象。
2015年

147

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


18
是的,在Java中不能覆盖静态方法确实是一种遗憾。
米歇尔

12
@Michel:有什么意义?如果要基于实例的行为,请使用实例方法。
冉·比隆

8
这个答案是不正确的。抽象类中的静态方法可以正常工作,并且很常用。只是类本身的静态方法可能不是抽象的。@Michel覆盖静态方法没有任何意义。没有实例,运行时如何知道要调用哪种方法?
erickson's

63
@erickson-即使没有实例,类层次结构也是完整的-静态方法的继承可以像实例方法的继承一样工作。Smalltalk做到了,它非常有用。
加里德(Jared)2009年

8
@matiasg一点也不新。始终允许抽象类具有静态的非抽象方法。
马特·鲍尔

70

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

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

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

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

ClassA.methodA();

methodA();

在SmallTalk中,类名不是可选的,因此语法是(请注意,SmallTalk不会使用。来分隔“主题”和“动词”,而是将其用作statemend终止符):

ClassA methodA.

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


1
“静态成员不能被子类覆盖”是错误的。至少在Java6中是可能的。不知道是什么时候。
史蒂文·德格罗特

15
@Steven De Groote静态成员确实不能被子类覆盖。如果子类的静态方法具有与超类中的静态方法相同的签名,则它不会覆盖它,而是将其隐藏。http://docs.oracle.com/javase/tutorial/java/IandI/override.html区别在于,多态仅适用于覆盖的方法,不适用于隐藏的方法。
约翰

2
@ John29感谢您的澄清,但是除了命名上的区别外,它的用法似乎相似。
史蒂文·德格罗特

2
@Steven De Groote是的,用法相似,但是行为不同。这就是为什么没有静态抽象方法的原因-如果静态抽象方法不支持多态性又有什么意义呢?
约翰

3
@Steven De Groote:当您在超类本身中调用该方法时,区别就显而易见。假设Super.foo调用Super.bar。如果子类实现Subclass.bar,然后调用foo,则foo仍将调用Super.bar,而不是Subclass.bar。因此,您真正拥有的是两个完全不同且不相关的方法,都称为“ bar”。这在任何有用的意义上都不能覆盖。
Doradus 2014年

14

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

既然Abstract类说了,它就不会给出实现,而允许子类来给出它

所以Subclass必须重写Superclass的方法,

RULE NO 1 - 静态方法不能被重写

因为静态成员和方法是编译时元素,所以为什么允许静态方法的Overloading(编译时多态)而不是Overriding(运行时多态)

因此,它们不能是Abstract。

没有什么像抽象静态 <--- Java Universe中不允许的


5
-1,“ Java不允许覆盖静态方法是不正确的,因为静态成员和方法是编译时元素”。静态类型检查是绝对有可能有abstract staticstackoverflow.com/questions/370962/...。Java不允许覆盖静态方法的真正原因是因为Java不允许覆盖静态方法。
Pacerier 2014年

重载与多态无关。重载和重载除了前缀“ over”外没有其他共同之处,这与Java和JavaScript都在其中包含“ Java”的方式几乎相同。方法的名称不是它的标识,它是签名。所以foo(String)不一样,仅foo(Integer)此而已。
曼队长

@CaptainMan重载在字面上称为“参数多态性”,因为根据参数的类型,会调用另一种称为多态性的方法。
达沃

12

这是一个糟糕的语言设计,实际上没有理由无法做到这一点。

事实上,这里是如何实现CAN在做JAVA

public class Main {

        public static void main(String[] args) {
                // This is done once in your application, usually at startup
                Request.setRequest(new RequestImplementationOther());

                Request.doSomething();
        }

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

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

        // Static methods in here can be overriden
        public static abstract class Request {

                abstract void doSomethingImpl();

                // Static method
                public static void doSomething() {
                        getRequest().doSomethingImpl();
                }

                private static Request request;
                private static Request getRequest() {
                        // If setRequest is never called prior, it will default to a default implementation. Of course you could ignore that too. 
                        if ( request == null ) {
                                return request = new RequestImplementationDefault();
                        }
                        return request;
                }
                public static Request setRequest(Request r){
                        return request = r;
                }

        }
}

=================下面的旧示例=================

查找getRequest,然后在进行调用之前可以调用getRequestImpl ... setInstance来更改实现。

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author Mo. Joseph
 * @date 16 mar 2012
 **/

public abstract class Core {


    // ---------------------------------------------------------------        
    private static Core singleton; 
    private static Core getInstance() {
        if ( singleton == null )
            setInstance( new Core.CoreDefaultImpl() );  // See bottom for CoreDefaultImpl

        return singleton;
    }    

    public static void setInstance(Core core) {
        Core.singleton = core;
    }
    // ---------------------------------------------------------------        



    // Static public method
    public static HttpServletRequest getRequest() {      
        return getInstance().getRequestImpl();
    }


    // A new implementation would override this one and call setInstance above with that implementation instance
    protected abstract HttpServletRequest getRequestImpl();




    // ============================ CLASSES =================================

    // ======================================================================
    // == Two example implementations, to alter getRequest() call behaviour 
    // == getInstance() have to be called in all static methods for this to work
    // == static method getRequest is altered through implementation of getRequestImpl
    // ======================================================================

    /** Static inner class CoreDefaultImpl */
    public static class CoreDefaultImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }
    }

     /** Static inner class CoreTestImpl : Alternative implementation */
    public static class CoreTestImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return new MockedRequest();
        }
    }       

}

用法如下:

static {
     Core.setSingleton(new Core.CoreDefaultImpl());

     // Or

     Core.setSingleton(new Core.CoreTestImpl());

     // Later in the application you might use

     Core.getRequest(); 

}

6
我不明白您在哪里提供abstract static了问题中所提出的方法的示例,而您以粗体写的可以在JAVA中完成。这完全是误导。
Blip

1
它本身不允许您将其定义为抽象静态,但是您可以实现类似的结果,从而可以使用此模式/ hack更改s静态方法的实现。这几乎没有误导。可以完成,但是使用不同的语义。
mmm

这是扩展抽象类,然后将静态方法放入子级的示例。无论如何,这都不是可以在JAVA中完成的示例。
水肺史蒂夫·史蒂夫,

2
@ScubaSteve首先,您的结论是错误的。其次,它达到相同的结果。意味着可以通过另一种实现方式更改对类的静态访问。这并不是说我使static关键字可抽象化的答案,但是使用此模式,您可以使用static方法,并且仍然可以更改其实现。虽然它确实仅具有全球化的负面影响,但是对于测试/生产/开发环境,它却为我们提供了诀窍。
mmm

5
  • 仅定义一个抽象方法,以便可以在子类中重写它。但是,静态方法不能被覆盖。因此,拥有抽象的静态方法是编译时错误。

    现在,下一个问题是为什么静态方法不能被覆盖?

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


4

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

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


4

我看到已经有数不胜数的答案,但是我没有任何实际的解决方案。当然,这是一个实际的问题,没有充分的理由在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
    }
}

doWork()C1C2中的方法相同。可能有很多这样的计算: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();
    }

1
因为在您的最终解决方案中,抽象类C没有任何静态方法,所以为什么不让C1和C2对其进行扩展并覆盖doMoreWork()方法,并让其他任何类创建其实例并调用所需的方法。基本上,您正在执行相同的操作,即使用匿名类扩展类C,然后使用其静态实例在C1和C2中进行扩展,以允许从静态方法中进行访问,但这根本不是必需的。
sactiw

我不了解您在此处提供的上下文。在最终解决方案中,您可以打电话C1.doWork()或,C2.doWork()但不能打电话C.doWork()。同样在您提供的示例中,如果它不起作用,则假设它不起作用,那么该类将如何C找到实现doMoreWork()?最后,我将您的上下文代码称为错误的设计。为什么?仅仅是因为您已经为唯一的代码创建了一个单独的函数,而不是为常见的代码创建了一个函数,然后在类中实现了静态函数C。这比较容易!!!
Blip

2

假设有两个类,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方法。


2

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


1
抽象类肯定可以具有静态方法。但不是静态的抽象方法。
JacksOnF1re

2

将方法声明为static意味着我们可以通过其类名来调用该方法,并且如果该类也是abstract如此,则由于没有任何主体而调用它是没有意义的,因此我们不能同时声明as staticabstract


2

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


1

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

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

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

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


1
并且可以在没有实例的情况下调用抽象静态方法,但是它将需要在子类中创建一个实现。它不是完全多态的,但是解决它的唯一方法是让具体的子对象实现一个“需要”“抽象静态”方法的接口。凌乱,但可行。
fijiaaron

3
实际上,我错了。接口中也不能有静态方法。语言缺陷。
fijiaaron

1

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

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

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

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

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

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

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

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

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


1

因为抽象类是OOPS概念,并且静态成员不是OOPS的一部分...。
现在,我们可以在接口中声明静态完整方法,并且可以通过在接口内部声明main方法来执行接口。

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

0

拥有抽象静态方法的想法是,您不能将特定的抽象类直接用于该方法,但只能使用一阶导数来实现该静态方法(或泛型:您所使用的泛型的实际类采用)。

这样,您可以创建例如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> 

可以检索类型,构建弹出菜单以选择要排序的类型,并通过从该类型获取数据来重新排序列表,还可以使用添加功能,当选择了排序类型时,该功能可以自动对新项目进行排序。请注意,SortableList实例可以直接访问静态方法“ T”:

String [] MenuItems = T.getSortableTypes();

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

奥拉夫(Chefio),奥拉夫(Olaf)。


0

首先,关于抽象类的关键点-无法实例化抽象类(请参阅wiki)。因此,您不能创建抽象类的任何实例。

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

因此,如果您无法实例化一个类,则该类将不能具有抽象静态方法,因为抽象方法会被扩展。

繁荣。


无论如何,抽象类中的每个方法都需要扩展其类才能执行,因此这不是借口。您可以扩展抽象类(同时实现抽象方法)。因此,这不能作为解释。
Pere

0

根据Java doc

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

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

一个很好的例子是:

list.sort(ordering);

代替

Collections.sort(list, ordering);

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

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));
    }    
}

0

因为“抽象”意味着要重写该方法,而不能覆盖“静态”方法。


该答案没有添加以前的答案尚未解决的任何内容。
MarsAtomic

@MarsAtomic我认为比最投票的答案更合适。而且,它是简洁的。
Praveen Kumar

然后,当您有足够的代表时,您可以编辑较早的答案以改善它们。您要做的就是通过创建重复的答案来增加信号的噪声。请遵循Stack Overflow既定的规则和习俗,而不要创建自己的规则并期望其他所有人遵循。
MarsAtomic

我不同意,请将我的答案与其他答案(尤其是最高投票的答案)比较。
Praveen Kumar

“为什么我不能这样做?” 答:“因为你做不到”。
JacksOnF1re 2016年

0

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

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



0

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


3
为什么会有问题呢?
eis

-1

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

这是关于它的官方文档:

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


2
怎么样?我一直在寻找解决方案,但找不到任何解决方案。
thouliha 2015年

?你不能。所有静态接口方法都必须使用接口类来调用。
mmm 2015年

8
这个答案是错误的,并且误导了Java新手。这的确显示了抽象静态方法的任何示例,因为它无法实现并在其他答案中阐明
Blip

-1

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


请大写并标出这个混乱的地方。
罗恩侯爵,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.