Reputation: 1349
Trying to understand why Java behaves differently in inferring the type and checking the type bounds when passing in type information using Class parameter.
With this code as an example:
public class TypeTest<T extends Number> {
Class<T> type;
TypeTest(Class<T> type) { this.type = type; }
static <S extends Number> void sMethod(Class<S> type) {}
<S extends Number> void method(Class<S> type) {}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
// 1.
TypeTest<Integer> obj = new TypeTest(Object.class); // compiles, unchecked call and assignment warnings
// 2.
obj.method(Object.class); // compile-time error, S not within bound
TypeTest obj1 = new TypeTest(Object.class); // compiles, unchecked call and assignment warnings
// 3.
obj1.method(Object.class); // compiles, unchecked call warning .
// 4.
TypeTest.sMethod(Object.class); // compile time error, Object not within bounds
// 5.
new TypeTest<Object>(Object.class); // compile time error, Object not within bounds
}
}
With static method (4.) we cannot pass in anything that is not a Number which seems the most natural behavior with the bounds provided.
However with a constructor (1., 5.) we have to specify the type parameter explicitely to get the same behavior as 4. Otherwise it seems T type parameter value is not inferred automatically from the Object.class variable.
Where does this difference comes from for constructor and static methods?
Another case which I do not understand completely is the difference between 2. and 3. Why the same operation compiles or does not compile only depending on the way of construction of the TypeTest object, while class type parameter T has no relation whatsoever to the method type parameter S?
Upvotes: 0
Views: 794
Reputation: 122439
Only generic types declared for a method or constructor can be inferred. So
<S> void method() {}
^ this can be inferred
<S> TypeTest() {}
^ this can be inferred
The generic type of a generic class cannot be inferred when constructing it:
class TypeTest<T> {}
^ this must be specified explicitly when using "new TypeTest"
or in Java 7 you can explicitly specify the diamond operator
As others have mentioned, when you use new TypeTest()
without any angle brackets, you are using a raw type. Raw types must work the same way that they worked prior to Generics, to preserve compatibility with old code. So the expression new TypeTest()
will have type TypeTest
(the raw type), not TypeTest<something>
.
Upvotes: 1
Reputation: 198093
When you omit a type parameter for a generic type -- that is, any time you type TypeTest
without a <Something>
-- Java ignores all generic checking for all of that type.
See http://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html for details.
Upvotes: 1
Reputation: 200158
new TypeTest(Object.class)
is an expression of the raw type TypeTest
, that's how it is designed. So of course, no type inference is done as there is no type to infer.
Upvotes: 1