abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
static
并不意味着“非空”的,那只是Java不允许静态方法是抽象的结果。它的意思是“可在类上调用”(它应该意味着“仅可在类上调用”,但这是另一个问题)。如果Java支持abstract static
方法,我期望它意味着1)该方法必须由子类实现,2)该方法是子类的类方法。一些方法作为实例方法就没有意义。不幸的是,在创建抽象基类(或接口)时,Java不允许您指定这一点。 - Michael Carman语言设计不佳。直接调用静态抽象方法比创建实例仅仅为了使用该抽象方法更有效。特别是在将抽象类作为枚举无法扩展的解决方法时,这一点尤其正确,这也是另一个糟糕的设计示例。希望他们在下一个版本中解决这些限制。
你无法覆盖静态方法,因此将其声明为抽象方法是没有意义的。此外,在抽象类中声明一个静态方法将使该方法属于该类,而不是覆盖该方法的类,所以无法使用。
abstract
注解应用于方法时,表示该方法必须在子类中被覆盖。static
成员(方法或字段)不能被子类重写(在其他面向对象语言中不一定如此,例如SmallTalk)。static
成员可以被隐藏,但这与重写根本不同。abstract
注解。ClassA.methodA();
和
methodA();
在SmallTalk中,类名是必需的,因此语法为(请注意,SmallTalk不使用“.”来分隔“主语”和“谓语”,而是将其用作语句终止符):ClassA methodA.
由于类名总是必需的,因此可以通过遍历类层次结构来确定方法的正确“版本”。值得一提的是,我偶尔会想念静态继承,并且在最初接触Java时缺乏静态继承而受到了伤害。此外,SmallTalk是鸭子类型的(因此不支持契约式编程)。因此,它没有类成员的抽象修饰符。
Operation
抽象类和几个操作子类,每个子类都有静态的 newReq()
和 newRsp()
,但是我无法在 Operation
类中声明抽象静态方法 newReq()
或 newRsp()
。 - zipper我也问过同样的问题,这是为什么:
因为抽象类表示不会提供实现并允许子类提供实现。
因此,子类必须重写超类的方法,
规则1 - 静态方法不能被重写
因为静态成员和方法是编译时元素,所以允许静态方法的重载(编译时多态)而不是重写(运行时多态)
所以它们不能是抽象的。
没有像abstract static这样的东西 <--- 在Java世界中不被允许
abstract static
可以进行静态类型检查,详见https://dev59.com/_3RC5IYBdhLWcg3wOeSB#rDAPoYgBc1ULPQZFFA4V 。Java不允许静态方法被覆盖的真正原因是因为Java本身不支持静态方法被覆盖。 - Pacerierfoo(String)
和foo(Integer)
并不相同,仅此而已。 - Captain Man这是一种糟糕的语言设计,而且没有理由不能实现。
事实上,在这里有一种模式或方法,可以在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
上执行此操作,并且能够针对每个线程上下文设置实例,而不是全局设置,如此处所示,然后就可以执行Request.withRequest(anotherRequestImpl, () -> { ... })
或类似操作。
现实世界通常不需要使用ThreadLocal
方法,通常只需能够全局地更改测试环境的实现即可。
请注意,这仅是一种模式,旨在通过稍微复杂的实现来解决通常无法修改的静态代码的问题,以便保留静态方法提供的直接、简单和干净的调用方法,并能够在需要时切换实现。
抽象静态
方法示例,并且你用粗体字写着 可以在Java中完成。这完全是误导。 - Blip抽象方法只定义在超类中以便可以在子类中被覆盖。然而,静态方法不能被覆盖。因此,在一个抽象的静态方法中编译时就会出错。
现在的问题是为什么静态方法不能被覆盖呢?
这是因为静态方法属于特定的类而不是它的实例。如果你尝试覆盖一个静态方法,你将不会得到任何编译或运行时错误,但编译器会隐藏超类的静态方法。
假设有两个类,Parent
和 Child
。其中 Parent
是抽象类。声明如下:
abstract class Parent {
abstract void run();
}
class Child extends Parent {
void run() {}
}
Parent
的实例必须指定如何执行run()
方法。Parent
不是abstract
。class Parent {
static void run() {}
}
Parent.run()
将执行静态方法。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
等。如果允许使用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();
}
C1.doWork()
或者C2.doWork()
,但是不能调用C.doWork()
。此外,在你提供的例子中,假设它被允许运行,那么C
类将怎样找到doMoreWork()
的实现呢?最后,我要说你所提供的上下文代码是一个糟糕的设计。为什么?因为你创建了一个独立的函数来处理唯一的代码,而不是为共同的代码创建一个函数,再在C
类中实现一个静态函数。这样更容易! - Blip