当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《为什么静态方法在Java中不能是抽象的》经验,为你挑选了7个好方法。

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

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

Tomalak.. 544

因为"abstract"意味着:"实现没有功能","静态"意味着:"即使你没有对象实例也有功能".这是一个合乎逻辑的矛盾.



1> Tomalak..:

因为"abstract"意味着:"实现没有功能","静态"意味着:"即使你没有对象实例也有功能".这是一个合乎逻辑的矛盾.


这不是一个逻辑上的矛盾,它是一种语言缺点,其他多种语言都支持这一概念."abstract"表示"在子类中实现","static"表示"在类而不是类实例上执行"没有逻辑矛盾.
一个更简洁的答案是"糟糕的语言设计".静态应该意味着"属于类",因为这就是它如何直观地使用,正如这个问题所表明的那样.请参阅Python中的"classmethod".
@Tomakak:你的逻辑是循环的.`static`并不意味着"不为空" - 这只是Java不允许静态方法抽象的结果.这意味着"可以在课堂上调用".(它应该意味着"只能在类上调用*",但这是另一个问题.)如果Java支持`abstract static`方法,我希望它意味着方法1)必须由子类实现,并且2)是一个子类的类方法.有些方法作为实例方法没有意义.遗憾的是,Java不允许您在创建抽象基类(或接口)时指定它.
@Tomalak我道歉,我不清楚.当然,静态方法'属于类'.尽管如此,它只是存在于同一名称空间中.静态方法不是类对象本身的方法:它不使用'this'作为类对象,并且它不能正确地参与继承链.如果真的是一个类方法`abstract static`就会很有意义.它是类对象本身的一种方法,子类对象必须实现它.当然,尽管我紧紧抓住语言,但事情的答案是正确的.
@Eric:和*仍然*,你说的不适用于`abstract static`:一个"在子类中实现"的函数X*不能*同时"在类上执行" - 只在*上子类*.那时它不再是抽象的了.
与Java中的许多东西一样,来自另一种语言似乎是一种限制,但后来你意识到这是你不应该做的事情.例如,在Leo的注释中,如果你需要知道继承的构造函数中的子类,那就是公然违反基本的OOP原则.另外,您如何提出这样的方法?要调用静态方法,您需要类名.使用基类名称,您如何知道您想要的子类?然而,如果您知道子类,那么开始时它不需要是抽象的.显示语法如何工作.
我同意@Eric.要成为一个逻辑矛盾,逻辑需要源于java规则之外.在java中,"static"可能是"功能,即使没有对象实例",但除了语言设计之外,这并不与"abstract"相矛盾.`int`表示'一个整数'而`[]`表示'一个数组',但Java知道我想从`int []`得到的东西并不意味着它自相矛盾,而是java的人类编写者决定允许某种功能与特定的语法排列相关联.
如果有一种方法可以调用它,你怎么知道抽象方法是否已实现?类必须在实例化之前实现所有抽象方法,但对于静态方法,不要实例化类.那么你怎么知道它是否是一个有效的电话?例如,在Delphi中,您可以创建静态抽象方法,但在调用此类方法时也可以在运行时获取异常.我总是喜欢编译时错误到运行时错误.就像我说的那样,似乎限制来自另一种语言,但Java正试图帮助你进行良好的设计.
@Pacerier想一想.*你怎么称呼它?三种方式:(1)直接使用子类名称,作为Child.Method - 但在这种情况下,它不需要是抽象的,因为你无论如何都指的是一个特定的子类名称; (2)通过一个物体 - 但它不需要是静止的; (3)通过带有反射的Class <?>实例 - 但是编译器不能保证Class实例具有定义的方法,如果在反映Parent时调用抽象方法,则现在遇到运行时异常.底线:需要静态抽象表示设计缺陷
诸如抽象静态方法之类的特征倾向于驱动不良设计.抽象方法的全部目的是允许模式,如方法工厂,模板方法等.这些是正确使用时的良好设计模式,并且由于OO语言的多态性质量而可用.另一方面,抽象静态方法除了强制子类实现某些东西之外没有其他功能,这明显违反了几个OO设计原则(例如OCP).
@Pacerier在父级中使其静态不太灵活,因为它意味着永远不允许子类使用它们的实例字段.非静态是一种更具可扩展性,可重复使用的设计.如果我需要在没有实例(通常是实用方法)的情况下调用它的方便性,我只会使它静态.如果我只打算像你提供的场景那样针对实例调用方法,我会把它变成非静态的.实例方法更灵活*即使*语言确实支持静态方法的多态,因为它不会在子类上添加不必要的约束.
@Pacerier在什么理论基础上是静态的"默认"?听起来你刚刚做到了.也许在程序编程中; 实际上,我认为实例方法是默认的.无论如何,*为什么*?如果你正在调用一个实例,为什么你这么担心它是静态的呢?这有什么实际的区别?
那么为什么在文档中说明:"抽象类可能有静态字段和静态方法",而在这里它不能有一个?

2> 小智..:

语言设计不佳.直接调用静态抽象方法比仅使用该抽象方法创建实例会更有效.当使用抽象类作为枚举无法扩展的变通方法时尤其如此,这是另一个糟糕的设计示例.希望他们在下一个版本中解决这些限制.


Java充满了奇怪的局限性.只访问最终变量的闭包是另一个.其余的名单几乎无穷无尽.知道它们及其解决方法是Java程序员的工作.为了获得乐趣,我们必须在业余时间使用比Java更好的东西.但我不会打扰.这是取得进步的种子.
我相信你所说的"糟糕的语言设计"实际上更像是一种"保护性语言设计",其目的是限制程序员因不必要的语言特征而导致的OO原则违规.
"抽象静态"概念是否违反OO原则?
@threed,完全没有,但当然有人说只有"静态"本身的概念已经违反了....
对静态的需求清楚地证明了"OO原则"并不像通常声称的那样包罗万象.

3> GaryF..:

您不能覆盖静态方法,因此将其抽象化将毫无意义.此外,在抽象类的静态方法将属于这个阶层,而不是覆盖类,因此无法使用反正.


@erickson - 即使没有实例,类层次结构也是完整的 - 静态方法的继承可以像实例方法的继承一样工作.Smalltalk做到了,它非常有用.
是的,在Java中无法覆盖静态方法的方式真的很遗憾.
@Michel:重点是什么?如果您想要基于实例的行为,请使用实例方法.
这个答案是不正确的.抽象类中的静态方法工作正常并且是常用的.这只是类本身的静态方法可能不是抽象的.@Michel覆盖静态方法没有意义.没有实例,运行时如何知道调用哪个方法?
@matiasg这根本不是什么新鲜事.总是允许抽象类具有static,_non-abstract_方法.
好消息.从java 7的官方文档(参见http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html):"抽象类可能有静态字段和静态方法.您可以使用这些静态成员类引用 - 例如,AbstractClass.staticMethod() - 就像你对任何其他类一样."

4> Jared..:

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

在Java中,static子类不能覆盖成员(方法或字段)(在其他面向对象的语言中不一定如此,请参阅SmallTalk.)static成员可能被隐藏,但这与被覆盖的根本不同.

由于静态成员无法在子类中重写,abstract因此无法将注释应用于它们.

另外 - 其他语言确实支持静态继承,就像实例继承一样.从语法的角度来看,这些语言通常需要将类名包含在语句中.例如,在Java中,假设您在ClassA中编写代码,这些是等效语句(如果methodA()是静态方法,并且没有具有相同签名的实例方法):

ClassA.methodA();

methodA();

在SmallTalk中,类名不是可选的,因此语法是(请注意,SmallTalk不使用.来分隔"主题"和"动词",而是将其用作statemend终结符):

ClassA methodA.

由于始终需要类名,因此始终可以通过遍历类层次结构来确定方法的正确"版本".对于它的价值,我偶尔会错过static继承,并且当我第一次开始使用Java时,由于缺乏静态继承而被咬了.另外,SmallTalk是鸭子类型(因此不支持逐个程序.)因此,它没有abstract类成员的修饰符.


@Steven De Groote一个静态成员实际上不能被子类覆盖.如果子类具有与超类中的静态方法具有相同签名的静态方法,则它不会覆盖它,它会隐藏它.[http://docs.oracle.com/javase/tutorial/java/IandI/override.html](http://docs.oracle.com/javase/tutorial/java/IandI/override.html)不同之处在于多态性仅适用于重写,但不适用于隐藏方法.
@Steven De Groote:当您在超类本身中调用该方法时,差异就会变得明显.假设Super.foo调用Super.bar.如果子类实现Subclass.bar,然后调用foo,那么foo仍将调用Super.bar,而不是Subclass.bar.因此,你真正拥有的是两种完全不同且无关的方法,都被称为"bar".在任何有用的意义上,这都不是最重要的.
@ John29感谢您的澄清,但是除了命名上的区别外,它的用法似乎相似。
@Steven De Groote是的,它的用法相似,但行为不同.这就是为什么没有静态抽象方法的原因 - 如果静态抽象方法不支持多态,那么它的意义何在?

5> anshulkatta..:

我也问了同样的问题,这就是原因

从Abstract类开始说,它不会给出实现并允许子类给它

所以Subclass必须覆盖Superclass的方法,

RULE NO 1 - 无法覆盖静态方法

因为静态成员和方法是编译时元素,这就是为什么允许静态方法的重载(编译时多态)而不是覆盖(运行时多态)

所以,他们不能抽象.

没有抽象静态 <--- Java Universe中不允许的东西


-1,"Java不允许覆盖静态方法,因为静态成员和方法是编译时元素",这是不正确的.静态类型检查绝对可以使用`abstract static`,参见http://stackoverflow.com/questions/370962/why-cant-static-methods-be-abstract-in-java/370967#comment40304607_370967.**为什么Java不允许重写静态方法的真正原因是因为Java不允许重写静态方法.

6> momomo..:

这是一个糟糕的语言设计,并没有理由为什么它不可能.

事实上,这里是如何实现CAN在做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();
        }
    }       

}


我不明白你在哪里提供了问题中提到的**"抽象静态"**方法的例子,你用粗体写的**可以用JAVA**.这完全是错误的.
@ScubaSteve首先,您的结论是错误的。其次,它达到相同的结果。意味着可以通过另一种实现方式更改对类的静态访问。这并不是说我使static关键字可抽象化的答案,但是使用此模式,您可以使用static方法,并且仍然可以更改其实现。虽然它确实仅具有全球化的负面影响,但是对于测试/生产/开发环境,它却为我们提供了诀窍。

7> 小智..:

仅定义抽象方法,以便可以在子类中重写它.但是,无法覆盖静态方法.因此,具有抽象的静态方法是编译时错误.

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

这是因为静态方法属于特定类而不属于其实例.如果您尝试覆盖静态方法,则不会得到任何编译或运行时错误,但编译器只会隐藏超类的静态方法.

推荐阅读
低调pasta_730
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有