Are following two signatures same?
public static void work(Class type, T instance);
and
public stati
For any set of arguments, if a valid choice of T
exists for
<T> void work(Class<T> type, T instance)
then a valid choice of T
and S
exists for
<T, S extends T> void work(Class<T> type, S instance)
and vice versa.
So from a theoretical point of view, they are equivalent. However, due to limited inference, it may be the case that, when type arguments are not given, one will compile while the other doesn't for certain arguments. In such a case, it is always possible to explicitly specify a valid set of type arguments for the case that doesn't compile, to make it compile.
Since they are equivalent, an API should always prefer the simpler form, i.e. without the S
.
No, the two signatures are not the same. From the Java Language Spec, Chapter 8:
Two methods have the same signature if they have the same name and argument types.
Two method or constructor declarations M and N have the same argument types if all of the following conditions hold:
- They have the same number of formal parameters (possibly zero)
- They have the same number of type parameters (possibly zero)
...
Since your two methods do not share the same number of type parameters, the signatures are not the same.
In practical cases where the methods are called with implicit type parameters, they might be seen as interchangeable. But this is only at the source level, never at the binary level. In other words, if you had the one-type-parameter version of work()
in class Foo
and it was called by a method in class Bar
, and then you switched to the two-type-parameter version of work()
and recompiled Foo
, you would also need to recompile Bar
.
@onepotato asks:
If they don't have the same signatures, then why when I copy and paste them in one class Eclipse tell me that they have the same method signature?
There is a difference between two signatures being equal and two signatures conflicting (being "override-equivalent"). Two signatures conflict if one is a subsignature of the other. This is explained later in the same section:
Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.
It is a compile-time error to declare two methods with override-equivalent signatures in a class.
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.
Just looking at the bytecode we can see that they do not:
For the first:
// access flags 0x9
// signature <T:Ljava/lang/Object;>(Ljava/lang/Class<TT;>;TT;)V
// declaration: void work<T>(java.lang.Class<T>, T)
public static work(Ljava/lang/Class;Ljava/lang/Object;)V
L0
LINENUMBER 86 L0
RETURN
L1
LOCALVARIABLE type Ljava/lang/Class; L0 L1 0
// signature Ljava/lang/Class<TT;>;
// declaration: java.lang.Class<T>
LOCALVARIABLE instance Ljava/lang/Object; L0 L1 1
// signature TT;
// declaration: T
MAXSTACK = 0
MAXLOCALS = 2
For the second:
// access flags 0x9
// signature <T:Ljava/lang/Object;S:TT;>(Ljava/lang/Class<TT;>;TS;)V
// declaration: void work<T, ST>( extends java.lang.Class<T>, S)
public static work(Ljava/lang/Class;Ljava/lang/Object;)V
L0
LINENUMBER 86 L0
RETURN
L1
LOCALVARIABLE type Ljava/lang/Class; L0 L1 0
// signature Ljava/lang/Class<TT;>;
// declaration: java.lang.Class<T>
LOCALVARIABLE instance Ljava/lang/Object; L0 L1 1
// signature TS;
// declaration: S
MAXSTACK = 0
MAXLOCALS = 2