首页 文章

为什么Java不允许覆盖静态方法?

提问于
浏览
465

为什么不能覆盖静态方法?

如果可能,请举例说明 .

22 回答

  • 4

    通过重写,我们可以根据对象类型创建多态性 . 静态方法与对象无关 . 所以java不支持静态方法覆盖 .

  • 2

    这个问题的答案很简单,标记为static的方法或变量只属于类,因此静态方法不能在子类中继承,因为它们只属于超类 .

  • 166

    覆盖取决于具有类的实例 . 多态性的一点是,您可以对类进行子类化,并且实现这些子类的对象将对超类中定义的相同方法具有不同的行为(并在子类中重写) . 静态方法与类的任何实例都没有关联,因此该概念不适用 .

    驱动Java设计的两个因素影响了这一点 . 一个是对性能的担忧:有很多人批评Smalltalk关于它太慢(垃圾收集和多态调用是其中的一部分)而Java的创建者决心避免这种情况 . 另一个决定是Java的目标受众是C开发人员 . 使静态方法的工作方式与C程序员熟悉,并且速度非常快,因为没有必要等到运行时才能找出要调用的方法 .

  • -3

    我个人认为这是Java设计中的一个缺陷 . 是的,是的,我知道非静态方法附加到实例,而静态方法附加到类等等 . 仍然,请考虑以下代码:

    public class RegularEmployee {
        private BigDecimal salary;
    
        public void setSalary(BigDecimal salary) {
            this.salary = salary;
        }
    
        public static BigDecimal getBonusMultiplier() {
            return new BigDecimal(".02");
        }
    
        public BigDecimal calculateBonus() {
            return salary.multiply(getBonusMultiplier());
        }
    
        /* ... presumably lots of other code ... */
    }
    
    public class SpecialEmployee extends RegularEmployee {
        public static BigDecimal getBonusMultiplier() {
            return new BigDecimal(".03");
        }
    }
    

    此代码无法正常工作 . 也就是说,SpecialEmployee就像普通员工一样获得2%的奖金 . 但如果你删除“静态”,那么SpecialEmployee就会获得3%的奖励 .

    (不可否认,这个例子的编码风格很差,因为在现实生活中你可能希望奖金乘数在某个地方而不是硬编码 . 但那只是因为我不想让这个例子陷入困境与该点无关的代码 . )

    我觉得你可能想让getBonusMultiplier保持静态似乎很合理 . 也许您希望能够显示所有类别员工的奖金乘数,而无需在每个类别中都有员工实例 . 搜索这样的示例实例有什么意义?如果我们正在创建一个新类别的员工而且还没有分配任何员工呢?这在逻辑上是一个静态函数 .

    但它不起作用 .

    是的,是的,我可以想到任何方法来重写上面的代码以使其工作 . 我的观点并不是它创造了一个无法解决的问题,而是它为那些粗心的程序员创造了一个陷阱,因为这种语言并不像我认为合理的人所期望的那样 .

    也许如果我尝试为OOP语言编写编译器,我很快就会明白为什么实现它以便可以重写静态函数是困难的或不可能的 .

    或者也许有一些很好的理由让Java以这种方式行事 . 任何人都可以指出这种行为的优势,某些类别的问题由此变得更容易吗?我的意思是,不要只指向Java语言规范并说“看,这记录了它的行为方式” . 我知道 . 但它有一个很好的理由,它应该以这种方式行事吗? (除了显而易见的“让它正常工作太难了”......)

    Update

    @VicKirk:如果你的意思是“糟糕的设计”,因为它不适合Java处理静态的方式,我的回答是,“嗯,当然,呃 . ”正如我在原帖中所说,它不起作用 . 但是,如果你的意思是设计不好,那么这种语言会有一些根本性的错误,即静态可以像虚函数一样被覆盖,这会以某种方式引入歧义或者不可能我回答说:“为什么?这个概念出了什么问题?”

    我认为我给出的例子是一件很自然的事情 . 我有一个类,它有一个不依赖于任何实例数据的函数,我可能非常合理地想要独立于实例调用,以及想要在实例方法中调用 . 为什么这不起作用?这些年来,我经常遇到这种情况 . 在实践中,我通过将函数设置为虚拟来解决它,然后创建一个静态方法,其生命中唯一的目的是将静态方法传递给具有虚拟实例的虚方法 . 这似乎是一个非常迂回的方式到达那里 .

  • 1

    简短的回答是:它完全有可能,但Java不会这样做 .

    以下是一些代码,用于说明Java中的 current state of affairs

    档案 Base.java

    package sp.trial;
    public class Base {
      static void printValue() {
        System.out.println("  Called static Base method.");
      }
      void nonStatPrintValue() {
        System.out.println("  Called non-static Base method.");
      }
      void nonLocalIndirectStatMethod() {
        System.out.println("  Non-static calls overridden(?) static:");
        System.out.print("  ");
        this.printValue();
      }
    }
    

    档案 Child.java

    package sp.trial;
    public class Child extends Base {
      static void printValue() {
        System.out.println("  Called static Child method.");
      }
      void nonStatPrintValue() {
        System.out.println("  Called non-static Child method.");
      }
      void localIndirectStatMethod() {
        System.out.println("  Non-static calls own static:");
        System.out.print("  ");
        printValue();
      }
      public static void main(String[] args) {
        System.out.println("Object: static type Base; runtime type Child:");
        Base base = new Child();
        base.printValue();
        base.nonStatPrintValue();
        System.out.println("Object: static type Child; runtime type Child:");
        Child child = new Child();
        child.printValue();
        child.nonStatPrintValue();
        System.out.println("Class: Child static call:");
        Child.printValue();
        System.out.println("Class: Base static call:");
        Base.printValue();
        System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
        child.localIndirectStatMethod();
        System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
        child.nonLocalIndirectStatMethod();
      }
    }
    

    如果你运行它(我在Mac上,从Eclipse,使用Java 1.6),你会得到:

    Object: static type Base; runtime type Child.
      Called static Base method.
      Called non-static Child method.
    Object: static type Child; runtime type Child.
      Called static Child method.
      Called non-static Child method.
    Class: Child static call.
      Called static Child method.
    Class: Base static call.
      Called static Base method.
    Object: static/runtime type Child -- call static from non-static method of Child.
      Non-static calls own static.
        Called static Child method.
    Object: static/runtime type Child -- call static from non-static method of Base.
      Non-static calls overridden(?) static.
        Called static Base method.
    

    在这里,唯一可能是惊喜(以及问题所在)的案例似乎是第一种情况:

    “运行时类型不用于确定调用哪些静态方法,即使使用对象实例( obj.staticMethod() )调用也是如此 . ”

    最后一个案例:

    “当从类的对象方法中调用静态方法时,静态方法selected是从类本身可访问的,而不是定义对象的运行时类型的类 . “

    使用对象实例调用

    静态调用在编译时解析,而非静态方法调用在运行时解析 . 请注意,虽然静态方法是从父级继承的,但它们不会被覆盖(由子级) . 如果你不这么想的话,这可能是一个惊喜 .

    从对象方法中调用

    使用运行时类型解析对象方法调用,但使用编译时(声明)类型解析静态(类)方法调用 .

    更改规则

    要更改这些规则,以便在示例中调用最后一次调用 Child.printValue() ,静态调用必须在运行时提供类型,而不是编译器在编译时使用对象的声明类解析调用(或上下文) . 然后,静态调用可以使用(动态)类型层次结构来解析调用,就像今天的对象方法调用一样 .

    这很容易实现(如果我们改变Java:-O),并且根本不合理,但是,它有一些有趣的考虑因素 .

    主要考虑因素是我们需要决定哪些静态方法调用应该这样做 .

    目前,Java使用"quirk"语言将 obj.staticMethod() 调用替换为 ObjectClass.staticMethod() 调用(通常带有警告) . [注意: ObjectClassobj 的编译时类型 . ]这些是以这种方式覆盖的良好候选者,采用 obj 的运行时类型 .

    如果我们这样做会使方法体难以阅读:父类中的静态调用可能是动态"re-routed" . 为了避免这种情况,我们必须使用类名调用静态方法 - 这使得使用编译时类型层次结构(如现在)更明显地解决了调用 .

    调用静态方法的其他方法更棘手: this.staticMethod() 应与 obj.staticMethod() 相同,采用 this 的运行时类型 . 但是,这可能会导致现有程序出现一些令人头疼的问题,这些程序调用(显然是本地的)静态方法而没有装饰(可以说相当于 this.method() ) .

    那么简单的电话 staticMethod() 怎么样?我建议他们和今天一样,并使用本地类上下文来决定做什么 . 否则会产生很大的混乱 . 当然,这意味着如果 method 是非静态方法,则 method() 将表示 this.method() ,如果 method 是静态方法,则表示 ThisClass.method() . 这是混乱的另一个原因 .

    其他考虑因素

    如果我们改变了这种行为(并使静态调用可能是动态非本地的),我们可能想要重新审视 finalprivateprotected 的含义作为类的 static 方法的限定符 . 然后我们都必须习惯 private staticpublic final 方法没有被覆盖的事实,因此可以在编译时安全地解析,并且"safe"作为本地引用读取 .

  • 1

    其实我们错了 .
    尽管Java默认情况下不允许您覆盖静态方法,但如果仔细查看Java中的类和方法类的文档,您仍然可以通过以下解决方法找到模拟静态方法覆盖的方法:

    import java.lang.reflect.InvocationTargetException;
    import java.math.BigDecimal;
    
    class RegularEmployee {
    
        private BigDecimal salary = BigDecimal.ONE;
    
        public void setSalary(BigDecimal salary) {
            this.salary = salary;
        }
        public static BigDecimal getBonusMultiplier() {
            return new BigDecimal(".02");
        }
        public BigDecimal calculateBonus() {
            return salary.multiply(this.getBonusMultiplier());
        }
        public BigDecimal calculateOverridenBonus() {
            try {
                // System.out.println(this.getClass().getDeclaredMethod(
                // "getBonusMultiplier").toString());
                try {
                    return salary.multiply((BigDecimal) this.getClass()
                        .getDeclaredMethod("getBonusMultiplier").invoke(this));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            }
            return null;
        }
        // ... presumably lots of other code ...
    }
    
    final class SpecialEmployee extends RegularEmployee {
    
        public static BigDecimal getBonusMultiplier() {
            return new BigDecimal(".03");
        }
    }
    
    public class StaticTestCoolMain {
    
        static public void main(String[] args) {
            RegularEmployee Alan = new RegularEmployee();
            System.out.println(Alan.calculateBonus());
            System.out.println(Alan.calculateOverridenBonus());
            SpecialEmployee Bob = new SpecialEmployee();
            System.out.println(Bob.calculateBonus());
            System.out.println(Bob.calculateOverridenBonus());
        }
    }
    

    结果输出:

    0.02
    0.02
    0.02
    0.03
    

    我们想要实现的目标:)

    即使我们将第三个变量Carl声明为RegularEmployee并将其分配给SpecialEmployee的实例,我们仍将在第一种情况下调用RegularEmployee方法并在第二种情况下调用SpecialEmployee方法

    RegularEmployee Carl = new SpecialEmployee();
    
    System.out.println(Carl.calculateBonus());
    System.out.println(Carl.calculateOverridenBonus());
    

    只看输出控制台:

    0.02
    0.03
    

    ;)

  • 1

    覆盖Java只是意味着将根据对象的运行时类型调用特定方法,而不是基于它的编译时类型(在重写静态方法的情况下) . 由于静态方法是类方法,因此它们不是实例方法,因此它们与引用指向哪个Object或实例的事实无关,因为由于静态方法的性质,它属于特定类 . 您可以在子类中重新声明它,但是该子类赢得了't know anything about the parent class'静态方法,因为正如我所说,它仅特定于已声明它的类 . 使用对象引用访问它们只是一种额外的自由Java的设计者,我们当然不应该想到只有当他们限制更多的细节和例子时停止这种做法http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html

  • 3

    静态方法被JVM视为全局方法,根本没有绑定到对象实例 .

    从概念上讲,如果你可以从类对象中调用静态方法(比如像Smalltalk这样的语言),那么在Java中就不是这样了 .

    EDIT

    你可以重载静态方法,没关系 . 但是你不能覆盖静态方法,因为类不是第一类对象 . 您可以使用反射在运行时获取对象的类,但是您获得的对象与类层次结构并不相同 .

    class MyClass { ... }
    class MySubClass extends MyClass { ... }
    
    MyClass obj1 = new MyClass();
    MySubClass obj2 = new MySubClass();
    
    ob2 instanceof MyClass --> true
    
    Class clazz1 = obj1.getClass();
    Class clazz2 = obj2.getClass();
    
    clazz2 instanceof clazz1 --> false
    

    你可以反思课程,但它会停在那里 . 您不使用 clazz1.staticMethod() 调用静态方法,而是使用 MyClass.staticMethod() . 静态方法没有绑定到对象,因此静态方法中没有 thissuper 的概念 . 静态方法是一个全局函数;因此,也没有多态性的概念,因此,方法覆盖是没有意义的 .

    但是,如果 MyClass 是运行时调用方法的对象,那么这可能是可能的,就像在Smalltalk中一样(或者JRuby可能就像一条评论所暗示的那样,但我对JRuby一无所知) .

    哦,是的......还有一件事 . 你可以通过一个对象 obj1.staticMethod() 来调用一个静态方法,但这应该是 MyClass.staticMethod() 的语法糖,应该避免 . 它通常会在现代IDE中引发警告 . 我不知道为什么他们允许这个捷径 .

  • 4

    方法覆盖是由dynamic dispatching实现的,这意味着对象的声明类型不确定它的行为,而是它的运行时类型:

    Animal lassie = new Dog();
    lassie.speak(); // outputs "woof!"
    Animal kermit = new Frog();
    kermit.speak(); // outputs "ribbit!"
    

    尽管 lassiekermit 都声明为 Animal 类型的对象,但它们的行为(方法 .speak() )会有所不同,因为动态调度只会在运行时调用 .speak() 到实现 - 而不是在编译时 .

    现在,这里是 static 关键字开始有意义的地方: the word "static" is an antonym for "dynamic". 所以你不能覆盖静态方法的原因是因为静态成员没有动态调度 - because static literally means "not dynamic". 如果它们动态调度(因此可以覆盖) static 关键字只是没有意义了 .

  • 444

    是 . 实际上Java允许重写静态方法,理论上如果你在Java中覆盖静态方法然后它将编译并运行顺利,但它将失去多态性,这是Java的基本属性 . 您将在任何地方阅读,无法尝试自己编译和运行 . 你会得到你的答案 . 例如如果你有类动物和一个静态方法eat(),你覆盖它的子类中的静态方法让它叫做Dog . 然后当你将Dog对象分配给Animal Reference并根据Java Dog调用eat()时,应该调用eat(),但是在静态覆盖动物'eat()中将被调用 .

    class Animal {
        public static void eat() {
            System.out.println("Animal Eating");
        }
    }
    
    class Dog extends Animal{
        public static void eat() {
            System.out.println("Dog Eating");
        }
    }
    
    class Test {
        public static void main(String args[]) {
           Animal obj= new Dog();//Dog object in animal
           obj.eat(); //should call dog's eat but it didn't
        }
    }
    
    
    Output Animal Eating
    

    根据Java的多态性原理,输出应该是 Dog Eating .
    但结果是不同的,因为支持Polymorphism Java使用Late Binding,这意味着只在运行时调用方法,而在静态方法的情况下不调用 . 在静态方法中,编译器在编译时调用方法而不是运行时,所以我们根据引用获取方法而不是根据对象引用a包含's why You can say Practically it supports static overring but theoretically, it doesn't .

  • 5

    在Java(和许多OOP语言,但我不能说话;有些根本没有静态)所有方法都有固定的签名 - 参数和类型 . 在虚方法中,隐含第一个参数:对对象本身的引用,当从对象内部调用时,编译器会自动添加 this .

    静态方法没有区别 - 它们仍然具有固定的签名 . 但是,通过声明方法static,您已明确声明编译器不得在该签名的开头包含隐含的对象参数 . 因此,调用它的任何其他代码必须不得尝试在堆栈上引用对象 . 如果它确实这样做了,那么方法执行将不起作用,因为参数将在堆栈上的错误位置 - 移位1 .

    因为这两者之间存在差异;虚方法始终具有对上下文对象的引用(即 this ),因此可以引用堆中属于该对象实例的任何内容 . 但是使用静态方法,由于没有传递引用,该方法无法访问任何对象变量和方法,因为上下文未知 .

    如果您希望Java更改定义以便为每个方法(静态或虚拟)传入对象上下文,那么您实际上只有虚拟方法 .

    正如有人在评论中提到的那样 - 你想要这个功能的原因和目的是什么?

    我不太了解Ruby,因为OP提到了这一点,我做了一些研究 . 我看到在Ruby类中实际上是一种特殊的对象,可以创建(甚至是动态的)新方法 . 类是Ruby中的完整类对象,它们不是Java . 这只是使用Java(或C#)时必须接受的内容 . 这些不是动态语言,尽管C#正在添加某些形式的动态语言 . 实际上,就我所能找到的而言,Ruby没有“静态”方法 - 在这种情况下,这些是单例类对象上的方法 . 然后,您可以使用新类重写此单例,并且前一个类对象中的方法将调用新类中定义的那些(正确吗?) . 因此,如果在原始类的上下文中调用方法,它仍然只执行原始静态,但调用派生类中的方法,将从父类或子类调用方法 . 有意思,我可以看到一些 Value . 它需要一种不同的思维模式 .

    由于您使用的是Java,因此需要适应这种做事方式 . 为什么他们这样做?那么,可能是基于可用的技术和理解来提高当时的性能 . 计算机语言在不断发展 . 回去足够远,没有OOP这样的东西 . 将来会有其他新想法 .

    EDIT :另一条评论 . 现在我看到了差异,而且作为我自己的Java / C#开发人员,我可以理解为什么如果你来自像Ruby这样的语言,你从Java开发人员那里得到的答案可能会令人困惑 . Java static 方法不一样Ruby class 方法 . Java开发人员很难理解这一点,相反,那些主要使用Ruby / Smalltalk等语言的人也是如此 . 我可以看到,由于Java还使用"class method"作为另一种讨论静态方法的方式,这也会让人感到非常困惑,但这个术语在Ruby中使用的方式不同 . Java没有Ruby样式类方法(对不起); Ruby没有Java风格的静态方法,它们实际上只是旧的过程风格函数,如C中所见 .

    顺便说一句 - 谢谢你的问题!我今天为我学习了一些关于类方法(Ruby风格)的新东西 .

  • 2

    好吧......如果你从一个重写方法应该如何在Java中运行的角度思考,答案是否定的 . 但是,如果尝试覆盖静态方法,则不会出现任何编译器错误 . 这意味着,如果你试图覆盖,Java并不会阻止你这样做;但你肯定没有得到与非静态方法相同的效果 . 在Java中覆盖只是意味着将根据对象的运行时类型调用特定方法,而不是根据它的编译时类型调用(覆盖静态方法就是这种情况) . 好的...有什么猜测他们为什么表现得很奇怪?因为它们是类方法,因此只能使用编译时类型信息在编译期间解析对它们的访问 . 使用对象引用访问它们只是Java设计者给出的额外自由,我们当然不应该只考虑限制它时停止该实践:-)

    Example :让我们试着看看如果我们尝试覆盖静态方法会发生什么: -

    class SuperClass {
    // ......
    public static void staticMethod() {
        System.out.println("SuperClass: inside staticMethod");
    }
    // ......
    }
    
    public class SubClass extends SuperClass {
    // ......
    // overriding the static method
    public static void staticMethod() {
        System.out.println("SubClass: inside staticMethod");
    }
    
    // ......
    public static void main(String[] args) {
        // ......
        SuperClass superClassWithSuperCons = new SuperClass();
        SuperClass superClassWithSubCons = new SubClass();
        SubClass subClassWithSubCons = new SubClass();
    
        superClassWithSuperCons.staticMethod();
        superClassWithSubCons.staticMethod();
        subClassWithSubCons.staticMethod();
        // ...
    }
    }
    

    Output : -
    SuperClass: inside staticMethod
    SuperClass: inside staticMethod
    SubClass: inside staticMethod

    注意输出的第二行 . 如果staticMethod被覆盖,则该行应该与第三行相同,因为我们在运行时类型的对象上调用'staticMethod()'作为'SubClass'而不是'SuperClass' . 这确认了静态方法总是仅使用其编译时类型信息来解析 .

  • 4

    通常,允许“覆盖”静态方法没有意义,因为没有好的方法来确定在运行时调用哪一个 . 以Employee为例,如果我们调用RegularEmployee.getBonusMultiplier() - 应该执行哪个方法?

    在Java的情况下,可以想象一种语言定义,只要通过对象实例调用静态方法,就可以“覆盖”静态方法 . 但是,所有这一切都将重新实现常规类方法,为语言添加冗余而不会真正增加任何好处 .

  • 23

    覆盖保留给实例成员以支持多态行为 . 静态类成员不属于特定实例 . 相反,静态成员属于该类,因此不支持覆盖,因为子类仅继承受保护的和公共实例成员而不是静态成员 . 您可能希望定义一个表面并研究工厂和/或策略设计模式,以评估替代方法 .

  • 7

    我喜欢和Jay的评论(https://stackoverflow.com/a/2223803/1517187) .
    我同意这是Java的糟糕设计 .
    正如我们在之前的评论中所看到的,许多其他语言都支持覆盖静态方法 . 我觉得周杰伦也像我一样从德尔福来到Java .
    Delphi(Object Pascal)是第一个实现OOP的语言 .
    很明显,很多人都有使用该语言的经验,因为它是过去编写商业GUI产品的唯一语言 . 并且 - 是的,我们可以在Delphi中覆盖静态方法 . 实际上,Delphi中的静态方法称为"class methods",而Delphi具有"Delphi static methods"的不同概念,它们是具有早期绑定的方法 . 要覆盖必须使用后期绑定的方法,请声明"virtual"指令 . 所以它非常方便直观,我希望用Java .

  • -1

    通过重写,您可以实现动态多态 . 当你说覆盖静态方法时,你试图使用的词是矛盾的 .

    静态说 - 编译时,覆盖用于动态多态 . 两者本质上相反,因此不能一起使用 .

    当程序员使用对象并访问实例方法时,会出现动态多态行为 . JRE将根据您使用的对象类型映射不同类的不同实例方法 .

    当你说覆盖静态方法时,我们将通过使用类名来访问静态方法,类名将在编译时链接,因此没有概念在运行时将方法与静态方法联系起来 . 所以术语“重写”静态方法本身并没有任何意义 .

    注意:即使您使用对象访问类方法,仍然java编译器足够智能以找到它,并将进行静态链接 .

  • 2

    覆盖静态方法有什么用呢?您无法通过实例调用静态方法 .

    MyClass.static1()
    MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.
    

    编辑:看来,通过语言设计中的不幸疏忽,你 can 通过一个实例调用静态方法 . 一般没有人这样做 . 我的错 .

  • 38

    简单的解决方案:使用单例实例 . 它将允许覆盖和继承 .

    在我的系统中,我有SingletonsRegistry类,它返回传递Class的实例 . 如果未找到实例,则会创建该实例 .

    Haxe语言课:

    package rflib.common.utils;
    import haxe.ds.ObjectMap;
    
    
    
    class SingletonsRegistry
    {
      public static var instances:Map<Class<Dynamic>, Dynamic>;
    
      static function __init__()
      {
        StaticsInitializer.addCallback(SingletonsRegistry, function()
        {
          instances = null;
        });
    
      } 
    
      public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
      {
        if (instances == null) {
          instances = untyped new ObjectMap<Dynamic, Dynamic>();      
        }
    
        if (!instances.exists(cls)) 
        {
          if (args == null) args = [];
          instances.set(cls, Type.createInstance(cls, args));
        }
    
        return instances.get(cls);
      }
    
    
      public static function validate(inst:Dynamic, cls:Class<Dynamic>)
      {
        if (instances == null) return;
    
        var inst2 = instances[cls];
        if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it's singleton!";
      }
    
    }
    
  • 1

    静态方法,变量,块或嵌套类 belongs to the entire class 而不是对象 .

    Java中的方法用于公开Object / Class的行为 . 这里,因为方法是 static (即,静态方法仅用于表示类的行为 . ) changing/ overriding 整个类的行为将违反面向对象编程的基本支柱之一的现象,即 high cohesion . (记住构造函数是Java中一种特殊的方法 . )

    High Cohesion - 一个 class 应该只有一个角色 . 例如:汽车类应该只 生产环境 汽车物品而不是自行车,卡车,飞机等 . 但是汽车类可能只有一些属于自己的特征(行为) .

    因此,在设计java编程语言时 . 语言设计者认为只允许开发人员将一个类的行为保留给自己,只需要将一个方法保持为静态 .


    下面的代码尝试覆盖静态方法,但 not 会遇到任何编译错误 .

    public class Vehicle {
    static int VIN;
    
    public static int getVehileNumber() {
        return VIN;
    }}
    
    class Car extends Vehicle {
    static int carNumber;
    
    public static int getVehileNumber() {
        return carNumber;
    }}
    

    这是因为,这里我们没有重写方法,但我们只是 re-declaring 它 . Java允许重新声明方法(静态/非静态) .

    从Car类的getVehileNumber()方法中删除static关键字将导致编译错误,因为,我们正在尝试 change 仅属于Vehicle类的静态方法的功能 .

    此外,如果getVehileNumber()声明为 final ,则代码将无法编译,因为final关键字限制程序员重新声明该方法 .

    public static final int getVehileNumber() {
    return VIN;     }
    

    总的来说,这是软件设计人员在哪里使用静态方法 . 我个人更喜欢使用静态方法来执行某些操作,而无需创建任何类的实例 . 其次,隐藏一个类的行为来自外部世界 .

  • 11

    这是一个简单的解释 . 静态方法与类关联,而实例方法与特定对象关联 . 覆盖允许调用与特定对象关联的重写方法的不同实现 . 因此,覆盖静态方法是违反直觉的,静态方法甚至与对象无关,而是首先与类本身相关联 . 因此,静态方法不能基于调用它的对象来覆盖,它将始终与创建它的类相关联 .

  • 16

    现在看到上面的答案,每个人都知道我们不能覆盖静态方法,但不应该误解 concept of accessing static methods from subclass .

    如果这个静态方法没有被子类中定义的新静态方法隐藏,我们可以使用子类引用访问超类的静态方法 .

    例如,见下面的代码: -

    public class StaticMethodsHiding {
        public static void main(String[] args) {
            SubClass.hello();
        }
    }
    
    
    class SuperClass {
        static void hello(){
            System.out.println("SuperClass saying Hello");
        }
    }
    
    
    class SubClass extends SuperClass {
        // static void hello() {
        // System.out.println("SubClass Hello");
        // }
    }
    

    输出: -

    SuperClass saying Hello
    

    有关在子类中隐藏静态方法的详细信息,请参阅Java oracle文档并搜索子类中的操作 .

    谢谢

  • 5

    以下代码显示可能:

    class OverridenStaticMeth {   
    
    static void printValue() {   
    System.out.println("Overriden Meth");   
    }   
    
    }   
    
    public class OverrideStaticMeth extends OverridenStaticMeth {   
    
    static void printValue() {   
    System.out.println("Overriding Meth");   
    }   
    
    public static void main(String[] args) {   
    OverridenStaticMeth osm = new OverrideStaticMeth();   
    osm.printValue();   
    
    System.out.println("now, from main");
    printValue();
    
    }   
    
    }
    

相关问题