Java Forum / General / July 2006
jdk 5 generic, why not the other way arround for (T[] e, Collection<T> c)
John_Woo - 15 Jul 2006 22:46 GMT Hi,
I'm trying to understand the generic concept. The following confused me:
public static void main(String arg[]) { Object[] oa = new Object [10]; Collection<Object> co = new ArrayList<Object>();
String[] sa = new String[10]; Collection<String> cs = new ArrayList<String>();
method(sa, co); //1 method(oa, co); //2
method(oa,cs); // 3, compile error: //<T>method(T[],java.util.Collection<T>) in Test cannot be applied to // (java.lang.Object[],java.util.Collection<java.lang.String>) // method(oa,cs); }
static <T> void method(T[]e, Collection<T> c) { //do nothing }
The #2 is obvious, but why #1 is ok and #3 is wrong?
-- Thanks John Toronto
Timo Stamm - 15 Jul 2006 23:05 GMT John_Woo schrieb:
> Hi, > [quoted text clipped - 22 lines] > > The #2 is obvious, but why #1 is ok and #3 is wrong? Imagine what would happen if this would compile, and your method did something:
static <T> void method(T[] e, Collection<T> c) { for (T t : e) { c.add(e); } }
Object[] oa = new Object [10]; Collection<String> cs = new ArrayList<String>(); method(oa, cs); String s = cs.get(cs.size()-1); // obviously an error
Timo
John_Woo - 15 Jul 2006 23:45 GMT > John_Woo schrieb: > > Hi, [quoted text clipped - 37 lines] > method(oa, cs); > String s = cs.get(cs.size()-1); // obviously an error Thanks, Timo, but how about this:
static <T> void method(T[] e, Collection<T> c) { e[0] = ((ArrayList)c).get(0); }
isn't that make the other way around?
Timo Stamm - 16 Jul 2006 00:55 GMT John_Woo schrieb:
>> Imagine what would happen if this would compile, and your method did >> something: [quoted text clipped - 18 lines] > > isn't that make the other way around? The point of Generics is to eliminate those casts. You should never use casts in parameterized code.
So you want to add a String to an Object-container. That's not a problem:
Object[] oa = new Object [10]; Collection<String> cs = new ArrayList<String>(); oa[0] = cs.iterator().next();
If you want to move the action into a seperate method, you have to express the type boundaries properly:
static <E, C extends E> void method(E[] e, Collection<C> c) { e[0] = c.iterator().next(); }
This method will add the first element of the Collection c to the array e, but the element type of c must be a sub class (or the same) of the element type of e.
If this confuses you, don't be frustrated. Generic types alone are more complicated than the whole type system of java 1.4.
Timo
John_Woo - 16 Jul 2006 12:49 GMT > John_Woo schrieb: > >> Imagine what would happen if this would compile, and your method did [quoted text clipped - 44 lines] > > Timo Thanks, Timo.
static <T> void a(T[] e, Collection<T> c) { e[0] = c.iterator().next(); }
static <T> void b(T[] e, Collection<T> c) { e[0] = (T)((ArrayList)c).get(0); }
Can u tell, why a passed comile, but b has unchecked or unsafe operations ? I meant in b, compiler should have known that all elements in array or in collection, are of type T.
Thomas Hawtin - 16 Jul 2006 20:38 GMT > static <T> void a(T[] e, Collection<T> c) { > e[0] = c.iterator().next(); [quoted text clipped - 9 lines] > in collection, > are of type T. There are two problems with b - the two casts. Casting to ArrayList removes the generic parameter, so is dubious. Casting T cannot be checked at runtime, so is unsafe.
What you can write is:
static <T> void c(T[] e, Collection<T> c) { e[0] = ((ArrayList<T>)c).get(0); }
Given a Collection<T> then if its erasure is at runtime an ArrayList it must be an ArrayList<T>.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Ingo R. Homann - 17 Jul 2006 09:55 GMT Hi Timo,
I think, Johns example is not so good (because his cast pointed you in a wrong direction). I think, Johns idea is correct, that your example (the other way round) would suffer the same problem:
Imagine what would happen if this would compile, and your method did something:
static <T> void method(T[] e, Collection<T> c) { int i=0; for (T t : c) { e[i++]=t; } }
String[] sa = new String[10]; Collection<Object> co = new ArrayList<Object>(); co.add(new Long(0)); method(sa, co); String s = sa[0]; // obviously an error
The point is (what Mike said): 'Arrays "know" [at runtime] what type they should contain; generics do not.'
I think this asymmetry between Arrays and generic Collections is a great design flaw. (Although I am aware that solving this is not easy and suffers other problems... one main problem is that a String[] can be assigned to an Object[]-variable: A String[] does not have all abilities of an Object[] (for example the ability to insert a Long), so it sould not be assignable!)
Ciao, Ingo
Mike Schilling - 16 Jul 2006 02:19 GMT > Hi, > [quoted text clipped - 22 lines] > > The #2 is obvious, but why #1 is ok and #3 is wrong? Arrays "know" what type they should contain; generics do not. Thus:
String [] sarr = new String[12]; Object[] oarr = sarr;
is safe, since
oarr[0] = new Object(); // throws exception at runtime.
With generics, on the other hand:
List<String> slist = new ArrayList<String>(); List<Object> olist = slist; // not allowed
is not safe, since
olist.add(new Object()); // no runtime exception
would not be prevented.
John_Woo - 16 Jul 2006 12:52 GMT > > Hi, > > [quoted text clipped - 42 lines] > > would not be prevented. Thanks, Mike.
So, can we make a top-level generics type for list, like
List<?> allList = new ArrayList<?>(); so it can accept of types of objects.
if possible, any example?
Thomas Hawtin - 16 Jul 2006 20:44 GMT > List<?> allList = new ArrayList<?>(); > so it can accept of types of objects. No, you would need:
List<Object> allList = new ArrayList<Object>();
? stands in for a particular generic argument, so you cannot create an object with a wildcard generic argument. (You can, however, create an object with a generic argument that contains a wildcard, such as new ArrayList<List<?>>().)
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Mike Schilling - 17 Jul 2006 07:50 GMT >> List<?> allList = new ArrayList<?>(); >> so it can accept of types of objects. [quoted text clipped - 7 lines] > object with a generic argument that contains a wildcard, such as new > ArrayList<List<?>>().) There are two different idea fighting it out here.
1. List<Object> is a list that can contain any sort of object.
2. List<?> is a reference that can refer to any list, regardless of what sort of object that list consists of.
They are quite different things. The fact that
Object[]
fulfills both for arrays serves to confuse things, but
new Object[12]
is the first idea, and
Object[] ref = new String[12]
is the second idea.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|