jdk 5 generic, why not the other way arround for (T[] e, Collection<T> c)

J

John_Woo

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?
 
T

Timo Stamm

John_Woo said:
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?


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
 
J

John_Woo

Timo said:
John_Woo said:
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?


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

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?
 
T

Timo Stamm

John_Woo said:
Timo said:
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

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?

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
 
M

Mike Schilling

John_Woo said:
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?

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.
 
J

John_Woo

Timo said:
John_Woo said:
Timo said:
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

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?

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

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.
 
J

John_Woo

Mike said:
John_Woo said:
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?

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.

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?
 
T

Thomas Hawtin

John_Woo said:
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.

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
 
T

Thomas Hawtin

John_Woo said:
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
 
M

Mike Schilling

Thomas Hawtin said:
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<?>>().)

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.
 
I

Ingo R. Homann

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,277
Latest member
VytoKetoReview

Latest Threads

Top