JDK-7023317 : The compiler allows a class with multiple methods the same signature.
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 6u24
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: linux
  • CPU: x86
  • Submitted: 2011-03-01
  • Updated: 2016-09-27
  • Resolved: 2016-09-27
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8Resolved
Related Reports
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :


A DESCRIPTION OF THE PROBLEM :
The JLS makes it clear that only the method name and parameter types distinguish a method's signature and return type and generics do not change this
http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.2

However if you use generics and a different return type, you can have miltiple methods with the same signature.
http://vanillajava.blogspot.com/2011/02/with-generics-return-type-is-part-of.html

For more context

http://stackoverflow.com/questions/5109146/does-the-method-parameters-with-different-generics-make-the-methods-have-differen/5109218#5109218

REGRESSION.  Last worked in version 6u24

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
create two method with the same method name and no arguements however give them different return types and different generic declarations and the program will still compile and run.  See the links provided.

Note: this has the same behaviour on IBM's R9 and OpenJDK latest.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Follow the JLS spec, or correct the JLS spec to match behaviour. (I prefer the later ;)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class Main {
    public static void main(String... args) {
        Main.<Integer>print();
        Main.<Short>print();
        Main.<Byte>print();
        Main.<Void>print();
    }

    public static <T extends Integer> int print() {
        System.out.println("here - Integer");
        return 0;
    }
    public static <T extends Short> short print() {
        System.out.println("here - Short");
        return 0;
    }
    public static <T extends Byte> byte print() {
        System.out.println("here - Byte");
        return 0;
    }
    public static <T extends Void> void print() {
        System.out.println("here - Void");
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Using Java 5.0 reports an eror for this code.

SUPPORT :
YES

Comments
To be clear, since this is somewhat lost in the discussion: the originally provided program is *not* legal, per JLS 3 (8.4.8.3), JLS 7, and JLS 8. It compiled (incorrectly) in javac 6, but not in javac 7 or javac 8. (I tested with 6u65, 7u51, and 8.) I'm not sure the following statement is any longer a concern: "A generic method can weasel out of being a subsignature of another method simply due to type parameter bounds." If there is any problem at all, we need a new example that passes both the 8.4.2 check and the 8.4.8.3 check, but that we don't want to be legal. Also note that any change made to the definition of "subsignature" and "same argument types" will be further-reaching than the 8.4.2 error check. It is fundamental to the overriding relationships between methods. (E.g., if "they erase to the same thing" were part of the definition of "subsignature", then a method "<T extends Integer> void m()" could override "<T extends String> void m()".)
31-07-2014

Two distinct problems have been identified: - JLS ch.8 has multiple rules for the same thing. - A generic method can weasel out of being a subsignature of another method simply due to type parameter bounds. Plan: 1. The rule in 8.4 is out of place. Its text is actually a more precise version of the rule in 8.4.2. Therefore, 8.4 should say nothing, and 8.4.2 should say "It is a compile-time error for the body of a class to declare two methods with override-equivalent signatures." 2. The definition of "same argument types" in 8.4.2 is silly. Two non-generic methods may be deemed to have the same argument types, and two generic methods with the same # of type parameters may be deemed to have the same argument types. But i) two generic methods with a different # of type parameters are never deemed to have the same argument types: <T extends Number> void foo(T x) {} <V extends Number, U extends Object> void foo(V x) {} and in fact ii) a generic method and a non-generic method are never deemed to have the same argument types, also because of the # of type parameters: <T extends Number> void foo(T x) {} void foo(Number x) {} The subsignature rule realizes for (ii) that foo(Number) is the erasure of foo(T) and therefore the methods are morally the same. But the subsignature rule cannot do the same for (i), since foo(V) is not literally the erasure of foo(T), and foo(T) is not literally the erasure of foo(V). We need the logic from "same argument type" to alpha-convert V to T and realize the second foo's type parameter bound and formal parameter type match those of the first foo - but that logic is only invoked when generic methods have literally the same # of type parameters. In practice, javac easily detects that foo(T) and foo(V) are morally the same. The concepts of subsignature and "same argument types" clearly need to be merged. It would be easy to say that corresponding argument types are the same if, assuming corresponding type parameters are unified, the argument types are the same or one is the erasure of the other. (In fact, JDK-4949438 indicates that "one is the erasure of the other" is actually "each contains the other", but ignore that for now.) However, 8.4.8.3 relies on "not a subsignature" to ensure that migration compatibility works properly. Migration compatibility allows a generified type in a superclass which is overridden by the erasure in the subclass. So List<String> can be overridden by List. Yet, List cannot be overridden by List<String>, and it is the "not a subsignature" clause which forbids it. List<String> is not a subsignature of List even though their erasures are the same, so 8.4.8.3 will raise a compile-time error. 8.4.8.3 can certainly be simplified to care about just a supertype and a subtype, rather than catching the case of two methods in the same type (which overlaps with 8.4.2). Still, it must complain when an argument type in the supertype is the erasure of the corresponding argument type in the subtype.
19-04-2013

Javac is currently rejecting the program on the basis that the methods have same erasure (meaning same erased parameter list). Let me know if we need to change this behavior. In any case we should probably move the bug back into the javac bucket or, in case javac is already correct and spec needs to change, we can keep this as a spec-only bug and have it assigned to you.
15-04-2013