问题是,在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?
}
当前回答
抽象类不能有静态方法,因为抽象是为了实现DYNAMIC BINDING,而静态方法是静态绑定到它们的功能上的。静态方法的意思是 行为不依赖于实例变量,因此没有实例/对象 是必需的。只是上课而已。静态方法属于类而不是对象。 它们存储在一个称为PERMGEN的内存区域中,每个对象都从这里共享它们。 抽象类中的方法动态地绑定到它们的功能上。
其他回答
我相信我已经找到了这个问题的答案,即为什么接口的方法(就像父类中的抽象方法一样工作)不能是静态的。以下是完整的答案(不是我的)
基本上静态方法可以在编译时绑定,因为要调用它们你需要指定一个类。这与实例方法不同,对于实例方法,在编译时调用方法的引用的类可能是未知的(因此只能在运行时确定调用哪个代码块)。
如果您正在调用一个静态方法,那么您已经知道实现它的类,或者它的任何直接子类。如果你定义
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中模仿它,让你至少能够修改自己的实现:
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方法,通常能够全局地改变测试环境的实现就足够了。
请注意,这样做的唯一目的是能够保留静态方法所提供的直接、轻松和干净地调用方法的能力,同时能够切换实现,以牺牲稍微复杂的实现为代价。
它只是一种绕过通常不可修改的静态代码的模式。
你不能重写静态方法,所以使它抽象是没有意义的。此外,抽象类中的静态方法将属于该类,而不是覆盖类,因此无论如何都不能使用。
我也问了同样的问题,原因如下
因为抽象类说,它不会给出实现,并允许子类给出它
所以子类必须重写超类的方法,
规则1 -静态方法不能被覆盖
因为静态成员和方法是编译时元素,这就是为什么允许重载(编译时多态性)静态方法而不是重写(运行时多态性)
所以它们不可能是抽象的。
Java宇宙中不允许有抽象静态<——之类的东西
我看到已经有无数的答案,但我没有看到任何实际的解决方案。当然,这是一个真正的问题,没有很好的理由在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
}
}
C1和C2中的doWork()方法相同。可能有很多这样的类:C3 C4等。如果允许静态抽象,你可以通过这样做来消除重复代码:
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
}
}
但这将无法编译,因为静态抽象组合是不允许的。 然而,这可以通过静态类构造来避免,这是允许的:
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();
}