简体   繁体   中英

Why does Java enforce return type compatibility for overridden static methods?

Per this answer and this answer , Java static methods aren't virtual and can't be overridden. Intuitively, therefore, this should work (even if in 99% of cases it's dangerous programming):

class Foo
{
    public static String frob() {
        return "Foo";
    }
}

class Bar extends Foo
{
    public static Number frob() {
        return 123;
    }
}

However, in practice this gets you:

Foo.java:10: frob() in Bar cannot override frob() in Foo; attempting to use incompatible return type
found   : java.lang.Number
required: java.lang.String
    public static Number frob() {
                         ^

Naively, it seems like Foo.frob() and Bar.frob() should have nothing to do with one another; yet Java insists that they do. Why?

(Nb: I don't want to hear why it would be a bad idea to code this way, I want to hear what it is in Java and/or the JVM design that makes this restriction necessary.)


Updated to add: For those who think the compiler's going to get confused by calling static methods on instances, if you allow this: it won't. It already has to figure this out in the case where the method signatures are compatible:

class Foo
{
    static String frob() {
        return "Foo";
    }
}

class Bar extends Foo
{
    static String frob() {
        return "Bar";
    }
}

class Qux {
    public static void main(String[] args) {
        Foo f = new Foo();
        Foo b = new Bar();
        Bar b2 = new Bar();

        System.out.println(f.frob());
        System.out.println(b.frob());
        System.out.println(b2.frob());
    }
}

gets you:

Foo
Foo
Bar

The question is, what's the concrete reason why it couldn't as easily (in the incompatible-signatures case) get you:

Foo
Foo
123

Consider the following:

public class Foo {
  static class A {
    public static void doThing() {
      System.out.println("the thing");
    }
  }

  static class B extends A {

  }

  static class C extends B {
    public static void doThing() {
      System.out.println("other thing");
    }
  }

  public static void main(String[] args) {
    A.doThing();
    B.doThing();
    C.doThing();
  }
}

Run it! It compiles and prints out

the thing
the thing
other thing

Static methods sort of inherit -- in the sense that B.doThing is translated into a call to A.doThing -- and can sort of be overridden.

This seems like it was mostly a judgement call for the JLS. The most specific way the JLS seems to address this, though, is section 8.2 , which simply doesn't say that static methods aren't inherited.

JLS 8.4.2 Method Signature , briefly:

Two methods have the same signature if they have the same name and argument types.

Nothing is said about staticness. Static methods can be called through an instance (or a null reference)--how should the method resolve if a subclass is referenced via a superclass declaration?

It is because in Java, a particular method is called based on the run time type of the object and not on the compile time type of it. However, static methods are class methods and hence access to them is always resolved during compile time only using the compile time type information. That is, what would happen if you could compile the above and use code like this

Foo bar = new Bar();
bar.frob();

Well, the JVM could probably be made to allow that, but let's talk about why it's a pretty bad idea from a compiler perspective.

The instance data (including which type the instance is) isn't something that is a simple problem to solve at compile time. Obviously it's well known at runtime. If I have a variable bar of type Bar, and I call s = bar.frob(), the compiler would need to reverse engineer what type bar is to see if the return value is acceptable. If determining the type at compile time is a super hard problem, this makes the compiler inefficient at best. At worst the answer is wrong and you get runtime errors that should have been caught at compile time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM