How do java generic methods constrain the method type arguments?

Extends Object which fits both types In order to achieve what you want, you'd need: private static void foo(Class clazz, T t1, T t2) then foo(String. Class, stringArray, stringArray); // compiles foo(String. Class, stringArray, integerArray); // fails.

Extends Object, which fits both types. In order to achieve what you want, you'd need: private static void foo(Class clazz, T t1, T t2); then foo(String. Class, stringArray, stringArray); // compiles foo(String.

Class, stringArray, integerArray); // fails.

As @Bozho has demonstrated the problem can be fixed, however to demonstrate what is going on consider this code: public class Main { // This is the original version that fails because of type erasure in arrays private static void foo(T t1, T t2) { t20 = t10; } // The same method as foo() but with the type erasure demonstrated private static void foo2(Object t1, Object t2) { // Integer should not contain String t20 = t10; } public static void main(String args) { String stringArray = new String{"1", "2", "3"}; Integer integerArray = new Integer{4, 5, 6}; foo2(stringArray, integerArray); } } This is all to do with the fact that arrays in Java are covariant, whereas generics are not. There is an interesting article about it here. A quick quote says it all: Arrays in the Java language are covariant -- which means that if Integer extends Number (which it does), then not only is an Integer also a Number, but an Integer is also a Number, and you are free to pass or assign an Integer where a Number is called for.(More formally, if Number is a supertype of Integer, then Number is a supertype of Integer.) You might think the same is true of generic types as well -- that List is a supertype of List, and that you can pass a List where a List is expected.

Unfortunately, it doesn't work that way. It turns out there's a good reason it doesn't work that way: It would break the type safety generics were supposed to provide. Imagine you could assign a List to a List.

Then the following code would allow you to put something that wasn't an Integer into a List: List li = new ArrayList(); List ln = li; // illegal ln. Add(new Float(3.1415)); Because ln is a List, adding a Float to it seems perfectly legal. But if ln were aliased with li, then it would break the type-safety promise implicit in the definition of li -- that it is a list of integers, which is why generic types cannot be covariant.

Up vote 3 down vote favorite 1 share g+ share fb share tw.

I've been reading about generic methods, and thought I understood how the generic type argument would constrain the method parameter types, but when I tested out some of the ideas with actual code, I got unexpected results. Here is a simple generic method that I don't understand: private static void foo(T t1, T t2){ t20 = t10; } ... String stringArray = new String{"1", "2", "3"}; Integer integerArray = new Integer{4,5,6}; foo(stringArray, integerArray); I would have thought that this generic method was constrained so that the two arrays had to be of the same type T, but in practice the code above compiles just fine, even though one array is of type String and the other is of type Integer. When the program runs, it generates a run-time exception (ArrayStoreException).

Java generics link|improve this question edited Nov 9 '10 at 22:00BalusC262k26272483 asked Nov 9 '10 at 21:56JavaSlugger161.

I'm not a java expert but I'm guessing the parser can't tell that foo() accepts 2 type Ts that have to be the same. It sees String is a type T and an Integer is also a type T. Which exactly should it use as T?

– Falmarri Nov 9 '10 at 22:02 Good answers all 'round. Well done SO'ers. – CurtainDog Nov 10 '10 at 1:07 @CurtainDog Many thanks we do our best ;-) – Gary Rowe Nov 10 '10 at 9:13.

A not-so-well-known fact about Java is that String is a subtype of Object (in contrast to List not being a subtype of List). Hence the compiler can infer T = Object, making the method signature foo(Object t1, Object t2) which can be called with foo(stringArray, integerArray). If you try the same with Lists: void foo(List t1, List t2) { ... } you will find that foo(new ArrayList(), new ArrayList()) doesn't compile - because there is no T such that both List and List are subtypes of List.

However, if instead you used wildcard types to declare the method: void foo(List t1, List t2) { ... } the method could be invoked (but the method body won't compile, because the compiler knows that the? May refer to incompatible types).

– EJP Nov 10 '10 at 1:32 Covariance of arrays is surprising to some - after all it violates Liskov's substitution priciple (neccessitating the existence of a runtime check that throws ArrayStoreException when it fails) and is in stark contrast to the invariance of generic types. – meriton Nov 10 '10 at 18:01.

As @Bozho has demonstrated the problem can be fixed, however to demonstrate what is going on consider this code: public class Main { // This is the original version that fails because of type erasure in arrays private static void foo(T t1, T t2) { t20 = t10; } // The same method as foo() but with the type erasure demonstrated private static void foo2(Object t1, Object t2) { // Integer should not contain String t20 = t10; } public static void main(String args) { String stringArray = new String{"1", "2", "3"}; Integer integerArray = new Integer{4, 5, 6}; foo2(stringArray, integerArray); } } This is all to do with the fact that arrays in Java are covariant, whereas generics are not. There is an interesting article about it here. A quick quote says it all: Arrays in the Java language are covariant -- which means that if Integer extends Number (which it does), then not only is an Integer also a Number, but an Integer is also a Number, and you are free to pass or assign an Integer where a Number is called for.

(More formally, if Number is a supertype of Integer, then Number is a supertype of Integer. ) You might think the same is true of generic types as well -- that List is a supertype of List, and that you can pass a List where a List is expected. Unfortunately, it doesn't work that way.

It turns out there's a good reason it doesn't work that way: It would break the type safety generics were supposed to provide. Imagine you could assign a List to a List. Then the following code would allow you to put something that wasn't an Integer into a List: List li = new ArrayList(); List ln = li; // illegal ln.

Add(new Float(3.1415)); Because ln is a List, adding a Float to it seems perfectly legal. But if ln were aliased with li, then it would break the type-safety promise implicit in the definition of li -- that it is a list of integers, which is why generic types cannot be covariant.

The compiler has inferred the type T for you and probably chosen Object. You can specify the type if necessary using the following syntax: MyClass. Foo(stringArray, integerArray); // Compiler error.

Combining arrays and generics is universally terrifying. By way of illustration I present Angelika Langer's Generics FAQ: angelikalanger.com/GenericsFAQ/FAQSectio....

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions