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

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

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

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

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

你不能重写一个静态方法,所以把它抽象化将是没有意义的。 此外,抽象类中的静态方法属于该类,而不是重写类,因此无法使用。

方法的abstract注释表明方法必须在子类中被重写。

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

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

顺便说一句 – 其他语言支持静态inheritance,就像实例inheritance一样。 从语法angular度来看,这些语言通常需要将类名包含在语句中。 例如,在Java中,假设你在ClassA中编写代码,这些是等价的语句(如果methodA()是一个静态方法,并且没有相同签名的实例方法):

 ClassA.methodA(); 

 methodA(); 

在SmallTalk中,类名不是可选的,所以语法是(注意,SmallTalk不使用。来分隔“subject”和“verb”,而是用它作为statemend终结符):

 ClassA methodA. 

由于类名始终是必需的,因此方法的正确“版本”始终可以通过遍历类层次来确定。 对于什么是值得的,我偶尔也会错过staticinheritance,而当我第一次使用静态inheritance的时候就被Java中的静态inheritance所困扰了。 此外,SmallTalk是duck-typed(因此不支持逐个合同)。因此,它没有对类成员的abstract修饰符。

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

由于抽象类说,它不会给实现,并允许子类给它

所以Subclass必须覆盖超类的方法,

规则1静态方法不能被覆盖

因为静态成员和方法是编译时间元素,所以允许使用静态方法的重载(编译时多态),而不是重载(运行时多态)

所以,他们不能成为摘要。

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

这是一个糟糕的语言devise,真的没有理由为什么它不可能。

实际上,这里是一个关于如何在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(); } } } 
  • 一个抽象方法的定义只能在一个子类中被覆盖。 但是,静态方法不能被覆盖。 因此,具有抽象的静态方法是编译时错误。

    现在接下来的问题是为什么静态方法不能被覆盖?

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

假设有两个类, 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方法真的没有太多的理由。

抽象类不能有静态方法,因为抽象是为了实现DYNAMIC BINDING,而静态方法是静态绑定到它们的function。静态方法意味着行为不依赖于实例variables,所以不需要实例/对象。只需要类。静态方法属于类而不是对象。 它们被存储在一个被称为PERMGEN的存储区域中,从那里与每个对象共享。 抽象类中的方法被dynamic绑定到它们的function。

您可以使用Java 8中的接口来完成此任务。

这是关于它的官方文档:

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

我看到已经有一个神奇的答案,但我没有看到任何实际的解决scheme。 当然这是一个真正的问题,在Java中排除这个语法没有什么好的理由。 由于原来的问题缺乏可能需要的背景,我提供了一个背景和一个解决scheme:

假设你在一堆相同的类中有一个静态方法。 这些方法调用一个类特定的静态方法:

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

C1C2中的doWork()方法是相同的。 可能有很多这样的cals: C3等等。如果允许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(); } } 

有了这个解决scheme,唯一重复的代码是

  public static void doWork() { c.doWork(); } 

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

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

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

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

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

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

如果你调用一个静态方法,你已经知道它实现的类,或者它的任何直接的子类。 如果你定义

 abstract class Foo { abstract static void bar(); } class Foo2 { @Override static void bar() {} } 

然后任何Foo.bar(); 调用显然是非法的,你将永远使用Foo2.bar();

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

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

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

因为“抽象”意味着方法被覆盖,而且不能覆盖“静态”方法。

根据定义,静态方法不需要知道this 。 因此,它不能是一个虚拟的方法(根据可用的dynamic子类信息来重载)。 相反,静态方法的重载仅仅基于编译时可用的信息(这意味着:一旦你引用了超类的静态方法,你就调用了超类方法,但从来不是子类方法)。

据此,抽象的静态方法将是非常无用的,因为你永远不会把它的引用replace成一个定义的主体。

有一个抽象的静态方法的想法是,你不能直接使用该特定的抽象类的方法,但只有一阶导数将被允许实现该静态方法(或generics:通用的实际类使用)。

这样,你可以创build一个sortableObject抽象类,甚至可以用(自动)抽象静态方法来定义sorting选项的参数:

 public interface SortableObject { public [abstract] static String [] getSortableTypes(); public String getSortableValueByType(String type); } 

现在你可以定义一个可sorting的对象,它可以被所有这些对象的主要typessorting:

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

现在你可以创build一个

 public class SortableList<T extends SortableObject> 

它可以检索types,build立一个popup菜单,select一个types进行sorting,并通过获取该types的数据,以及hainv添加function,当一个sortingtypes已被选中,可以自动请注意,SortableList的实例可以直接访问“T”的静态方法:

 String [] MenuItems = T.getSortableTypes(); 

不得不使用实例的问题是,SortableList可能还没有项目,但已经需要提供首选的sorting。

Cheerio,Olaf。

首先,关于抽象类的一个关键点 – 一个抽象类不能被实例化(参见wiki )。 所以,你不能创build任何抽象类的实例。

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

所以,如果你不能实例化一个类,那么这个类不能有抽象的静态方法,因为一个抽象的方法需要扩展。

繁荣。

根据Java 文档 :

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

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

一个很好的例子是:

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

常规方法可能是抽象的,当它们被子类覆盖并提供function时。 想象一下, Foo类是通过Bar1, Bar2, Bar3等扩展的。因此,每个抽象类都会根据自己的需要有自己的版本。

现在,静态方法根据定义属于类,它们与类的对象或其子类的对象无关。 他们甚至不需要它们存在,它们可以在没有实例化类的情况下使用。 因此,他们需要做好准备,不能依靠子类来增加function。

因为abstract是应用于Abstract方法的关键字,所以不指定body。 如果我们谈论静态关键字它属于类区域。

因为如果一个类扩展了一个抽象类,那么它就必须重写抽象方法,这是强制性的。 由于静态方法是在编译时解决的类方法,而重写的方法是在运行时parsing的实例方法,并遵循dynamic多态性。