问题是,在Java中为什么不能定义抽象静态方法?例如
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
问题是,在Java中为什么不能定义抽象静态方法?例如
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
当前回答
你不能重写静态方法,所以使它抽象是没有意义的。此外,抽象类中的静态方法将属于该类,而不是覆盖类,因此无论如何都不能使用。
其他回答
在一行中,这种危险的组合(抽象+静态)违反了面向对象的原则,即多态性。
在继承情况下,JVM将在运行时根据实现决定实例的类型(运行时多态性),而不是根据引用变量的类型(编译时多态性)。
@Overriding:
静态方法不支持@ override(运行时多态性),而只支持方法隐藏(编译时多态性)。
@Hiding:
但是在抽象静态方法的情况下,父(抽象)类没有方法的实现。因此,子类型引用是唯一可用的,而且它不是多态性。
子引用是唯一可用的:
出于这个原因(抑制oop特性),Java语言认为抽象+静态是非法(危险)的方法组合。
当常规方法要被子类覆盖并提供功能时,它们可以是抽象的。 假设类Foo由Bar1, Bar2, Bar3等扩展。因此,每个人都将根据自己的需要拥有自己的抽象类版本。
静态方法根据定义属于类,它们与类的对象或类的子类的对象无关。它们甚至不需要它们存在,它们可以在不实例化类的情况下使用。因此,它们需要准备就绪,不能依赖于子类向它们添加功能。
因为“抽象”的意思是:“不实现任何功能”,而“静态”的意思是:“即使你没有对象实例,也有功能”。这是一个逻辑矛盾。
因为abstract是应用于abstract方法上的关键字,所以abstract方法不指定主体。而静态关键字则属于类区域。
这是一个糟糕的语言设计,真的没有理由不可能。
事实上,这里有一个模式或方法可以在**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方法,通常能够全局地改变测试环境的实现就足够了。
请注意,这样做的唯一目的是能够保留静态方法所提供的直接、轻松和干净地调用方法的能力,同时能够切换实现,以牺牲稍微复杂的实现为代价。
它只是一种绕过通常不可修改的静态代码的模式。