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

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

当前回答

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

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

@Overriding:

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

@Hiding:

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

子引用是唯一可用的:

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

其他回答

根据Java文档:

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

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

一个很好的例子是:

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

这是一个糟糕的语言设计,真的没有理由不可能。

事实上,这里有一个模式或方法可以在**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();

这将允许您静态地调用方法,同时还能够更改例如Test环境的实现。

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

现实世界通常不需要ThreadLocal方法,通常能够全局地改变测试环境的实现就足够了。

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

它只是一种绕过通常不可修改的静态代码的模式。

你不能重写静态方法,所以使它抽象是没有意义的。此外,抽象类中的静态方法将属于该类,而不是覆盖类,因此无论如何都不能使用。

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

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

使用抽象静态方法的想法是,您不能直接为该方法使用特定的抽象类,但只允许一阶导数实现该静态方法(或者对于泛型:您使用的泛型的实际类)。

通过这种方式,您可以创建sortableObject抽象类甚至接口 使用(auto-)抽象静态方法,定义排序选项的参数:

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> 

它可以检索类型,构建一个弹出菜单来选择要排序的类型,并通过从该类型获取数据来返回列表,以及hainv一个add函数,当选择了排序类型时,可以自动对新项进行排序。 注意SortableList实例可以直接访问“T”的静态方法:

String [] MenuItems = T.getSortableTypes();

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

再见 奥拉夫。