19

Reading the Javadoc for the @Override annotation, I came across the following rule:

If a method is annotated with this annotation type compilers are required to generate an error message unless at least one of the following conditions hold:

  • The method does override or implement a method declared in a supertype.
  • The method has a signature that is override-equivalent to that of any public method declared in Object.

I'm clear on the first point, but I'm unsure about the second one.

What does it mean by "override-equivalent"? How are public methods of Object special in this respect? And why is this not covered under the first criterion?

Update note: This is only true of the Java 7 documentation. The Java 6 doc doesn't say anything about override-equivalence. Why the change?


Update:

After consulting the JLS (Section 8.4.2), I found the following explanation of override-equivalence:

The signature of a method m1 is a subsignature of the signature of a method m2 if either:

  • m2 has the same signature as m1, or
  • the signature of m1 is the same as the erasure (§4.6) of the signature of m2.

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.

As far as I can tell, this answers the first question ("What does it mean?") and the third question ("Why doesn't the first condition cover this?").

If I understand correctly (please inform me if I don't!), there is only one case where two methods are override-equivalent and which doesn't fall under the first condition of the original question. This is the case when the erasure of the signature of the subclass method is the same as the signature of the superclass method, but not the other way around.

The second condition of the original question, then, would only come into play when we attempt to add type parameters when attempting to "override" a public method of the Object class. I tried the following simple example to test this, with an unused type parameter:

public class Foo {
    @Override
    public <T> boolean equals(Object obj) {
        return true;
    }
}

Of course, this class doesn't compile, because the method doesn't actually override the equals method and thus clashes with it. But I also still receive an error for using the @Override annotation. Am I wrong in assuming that this is a valid example of the second condition for @Override usage? Or is the compiler generating this error despite not being required to?

Paul Bellora
  • 51,514
  • 17
  • 127
  • 176
Octahedron
  • 853
  • 2
  • 15
  • 30

2 Answers2

8

The reason for this is to allow you to use the @Override annotation in interfaces, which do not inherit from Object but implicitly declare all public methods from Object (see JLS section 9.2 interface members). You are thus allowed to declare an interface like:

interface Bar { @Override int hashCode(); }

However, you would not be allowed to declare the following interface:

interface Quux { @Override Object clone(); }

since the clone() method is not implicitly declared in an interface (it is not public).

This is described in JLS section 9.6.3.4 @Override (the Javadoc for @Override still refers to an old section number)

Didier L
  • 13,411
  • 5
  • 46
  • 90
  • Ah, that makes a ton of sense. Good to know about the implicit method declarations! Any idea why this condition was only included in the most recent docs, despite this usage working all the way back to 1.5? – Octahedron May 03 '13 at 22:45
  • I do not follow JLS evolutions (and actually it is the first time I get so deeply into the JLS!) but I would say to reflect what the compilers have actually implemented. – Didier L May 03 '13 at 22:56
  • 1
    Found a [blog post](https://blogs.oracle.com/ahe/entry/override_snafu) that seems to explain why it wasn't in the JDK 6 docs, at least. – Octahedron May 03 '13 at 23:27
  • 1
    For the record, the blog post link mentioned in @Octahedron's previous comment is now broken. [Here is the version from the Internet Archive](https://web.archive.org/web/20150915023148/https://blogs.oracle.com/ahe/entry/override_snafu). – Didier L Jul 09 '18 at 08:05
4

Your question is basically a design question and JLS explains its:

"The notion of subsignature is designed to express a relationship between two methods whose signatures are not identical, but in which one may override the other. Specifically, it allows a method whose signature does not use generic types to override any generified version of that method. This is important so that library designers may freely generify methods independently of clients that define subclasses or subinterfaces of the library."

Your code is not a valid example of this , see the below code it works:

public class SubSignatureTest extends SignatureTest {

    @Override
    public List test(Collection p) {
        return null;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

}

class SignatureTest {

    public <T> List<T> test(Collection<T> t) {
        return null;

    }
}

Whole point is that signature of superclass and subclass should be same after erasure.

EDIT: When we talk of override equivalence then parent class should have generic method and child class should have non generic method. Here is an example to explain this .Below code will not work because child class have generic method. For a moment lets assume that java allowed that then the call in main method will always fail :

class A{
       public int compareTo(Object o){
               return 0;
       }
}

class B extends A implements Comparable<B>{
       public int compareTo(B b){
               return 0;
       }

       public static void main(String[] argv){
               System.out.println(new B().compareTo(new Object()));
       }
}

In class B method will be like this after compilation:

public int compareTo(Object x){
    return compareTo((B)x);
  }

Which means this is always error: new B().compareTo(new Object()) . Therefore java will not allow child class to have generic method if parent class has non generic method. So you can't define override equivalence methods for object class.

Hope that clarifies.

I used the post http://lists.seas.upenn.edu/pipermail/types-list/2006/001091.html for reference, it has lot more details.

Lokesh
  • 7,500
  • 6
  • 39
  • 71
  • Fair enough, but where is the notion of a method whose signature is override-equivalent to that of a public method declared in `Object`, yet doesn't override that public method? – Octahedron Apr 28 '13 at 16:40
  • You cannot create override-equivalent method of object class methods because none of them is generic. When we talk of override equivalent methods then parent class should have generic and child class should have non generic method. See my edit for more details on this. – Lokesh Apr 29 '13 at 06:42
  • 1
    Very clear and detailed! But do you mean to imply that Oracle has somehow slipped an impossible condition into their `@Override` documentation? – Octahedron Apr 29 '13 at 16:44
  • They have not slipped any impossible condition. Its just that your attempt to create override equivalence method is not in line with that. Doc. states "The method has a signature that is override-equivalent to that of any public method declared in Object." and my first example proves it. – Lokesh Apr 30 '13 at 14:38
  • 2
    Maybe I'm misunderstanding you, but "You cannot create override-equivalent method of object class methods" and "The method has a signature that is override-equivalent to that of any public method declared in Object" seem to be contradictory. – Octahedron Apr 30 '13 at 15:48
  • 1
    "When we talk of override equivalence then parent class should have generic method and child class should have non generic method." I disagree - by definition the override-equivalence relation is symmetric. Your post is interesting, but doesn't appear to be relevant to the question. I think you're conflating override-equivalence and subsignatures. – bacar Feb 03 '14 at 18:52