Why doesn't Java allow overriding of static methods?

后端 未结 22 2694
谎友^
谎友^ 2020-11-21 05:49

Why is it not possible to override static methods?

If possible, please use an example.

22条回答
  •  再見小時候
    2020-11-21 06:29

    The short answer is: it is entirely possible, but Java doesn't do it.

    Here is some code which illustrates the current state of affairs in Java:

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

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

    If you run this (I did it on a Mac, from Eclipse, using Java 1.6) you get:

    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.
    

    Here, the only cases which might be a surprise (and which the question is about) appear to be the first case:

    "The run-time type is not used to determine which static methods are called, even when called with an object instance (obj.staticMethod())."

    and the last case:

    "When calling a static method from within an object method of a class, the static method chosen is the one accessible from the class itself and not from the class defining the run-time type of the object."

    Calling with an object instance

    The static call is resolved at compile-time, whereas a non-static method call is resolved at run-time. Notice that although static methods are inherited (from parent) they are not overridden (by child). This could be a surprise if you expected otherwise.

    Calling from within an object method

    Object method calls are resolved using the run-time type, but static (class) method calls are resolved using the compile-time (declared) type.

    Changing the rules

    To change these rules, so that the last call in the example called Child.printValue(), static calls would have to be provided with a type at run-time, rather than the compiler resolving the call at compile-time with the declared class of the object (or context). Static calls could then use the (dynamic) type hierarchy to resolve the call, just as object method calls do today.

    This would easily be doable (if we changed Java :-O), and is not at all unreasonable, however, it has some interesting considerations.

    The main consideration is that we need to decide which static method calls should do this.

    At the moment, Java has this "quirk" in the language whereby obj.staticMethod() calls are replaced by ObjectClass.staticMethod() calls (normally with a warning). [Note: ObjectClass is the compile-time type of obj.] These would be good candidates for overriding in this way, taking the run-time type of obj.

    If we did it would make method bodies harder to read: static calls in a parent class could potentially be dynamically "re-routed". To avoid this we would have to call the static method with a class name -- and this makes the calls more obviously resolved with the compile-time type hierarchy (as now).

    The other ways of invoking a static method are more tricky: this.staticMethod() should mean the same as obj.staticMethod(), taking the run-time type of this. However, this might cause some headaches with existing programs, which call (apparently local) static methods without decoration (which is arguably equivalent to this.method()).

    So what about unadorned calls staticMethod()? I suggest they do the same as today, and use the local class context to decide what to do. Otherwise great confusion would ensue. Of course it means that method() would mean this.method() if method was a non-static method, and ThisClass.method() if method were a static method. This is another source of confusion.

    Other considerations

    If we changed this behaviour (and made static calls potentially dynamically non-local), we would probably want to revisit the meaning of final, private and protected as qualifiers on static methods of a class. We would then all have to get used to the fact that private static and public final methods are not overridden, and can therefore be safely resolved at compile-time, and are "safe" to read as local references.

提交回复
热议问题