Yet Another ClassCastException Question

M

Michael Powe

I have an ArrayList initialized thus:

ArrayList<Date> entryDate = new ArrayList<Date>();

And used in this method:

Date [] sortEntryKeys(ArrayList entryDate){
Date [] sortedEntryDates = null;
Collections.sort(entryDate);
sortedEntryDates = (Date []) entryDate.toArray();
return sortedEntryDates;

The cast to sortedEntryDates throws a ClassCastException when the
method is invoked on an ArrayList of Date objects.

Why? I have another, clunky way of getting the dates into the array,
using System.arraycopy(), but I'd like to know why this way does not
work.

Thanks.

mp
 
P

Patrick

Michael Powe a écrit :
ArrayList<Date> entryDate = new ArrayList<Date>();

sortedEntryDates = (Date []) entryDate.toArray();

The cast to sortedEntryDates throws a ClassCastException when the
method is invoked on an ArrayList of Date objects.

The toArray method returns an array of Object, not Date. You must write:
sortedEntryDates = (Date []) entryDate.toArray(new Date[0]);

RTFM:
http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collection.html#toArray(T[])
 
M

Mike Schilling

Michael Powe said:
I have an ArrayList initialized thus:

ArrayList<Date> entryDate = new ArrayList<Date>();

And used in this method:

Date [] sortEntryKeys(ArrayList entryDate){
Date [] sortedEntryDates = null;
Collections.sort(entryDate);
sortedEntryDates = (Date []) entryDate.toArray();
return sortedEntryDates;

The cast to sortedEntryDates throws a ClassCastException when the
method is invoked on an ArrayList of Date objects.

Why? I have another, clunky way of getting the dates into the array,
using System.arraycopy(), but I'd like to know why this way does not
work.

You didn't tell toArray what sort of array to create, so it created an
Object[]. Try

sortedEntryDates = (Date []) entryDate.toArray(new
Date[entryDate.size()]);
 
M

Michael Powe

Mike> You didn't tell toArray what sort of array to create, so it
Mike> created an Object[]. Try

Mike> sortedEntryDates = (Date []) entryDate.toArray(new
Mike> Date[entryDate.size()]);

Okay, great, that worked. What am I missing about casting from Object
to Date? I've looked at some discussions of casting in my books but
it is not clear to me -- in fact, from my reading it would seem that
it should work. (converting object[] to date[]).

Thanks for the help.

mp
 
B

Bjorn Abelli

Michael Powe said:
What am I missing about casting from Object
to Date?

Probably nothing, but that's another casting.

Here you're trying to cast arrays: Object[] to Date[]

That casting would be okay, if the original array was *initialized* as a
Date[].

Some examples; to show the problem I instantiate two arrays:

Object[] oad = new Date[];

Object[] oao = new Object[];

Now we try to cast them:

The first cast will work, as it *is* a Date[].

Date[] dad = (Date[]) oad;

The second cast won't work, as there *could* be instances of other types in
the array, even if there isn't:

Date[] dao = (Date[]) oao; // Won't work!

That's why you need to provide the right type of array into ToArray when you
want a specific type of array.

// Bjorn A



Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
 
M

Mike Schilling

Michael Powe said:
Mike> You didn't tell toArray what sort of array to create, so it
Mike> created an Object[]. Try

Mike> sortedEntryDates = (Date []) entryDate.toArray(new
Mike> Date[entryDate.size()]);

Okay, great, that worked. What am I missing about casting from Object
to Date? I've looked at some discussions of casting in my books but
it is not clear to me -- in fact, from my reading it would seem that
it should work. (converting object[] to date[]).

Nothing. What you're missing is that arrays (unlike generic collections)
have actual run-time types. Object[] and Date[] are different types, just
as Object and Date are, and casting from the former to the latter can fail.

Object[] oa = new Object[1];
Date[] da = new Date[1];

Object[] oa2 = da; // allowed
Date[] da2 = (Date[])oa2; // works, since it's "really" a Date[]
Date[] da3 = (Date[])oa; // fails at runtime with a ClassCastException
// since it's "really" an Object[]
 
O

Oliver Wong

Bjorn Abelli said:
to show the problem I instantiate two arrays:

Object[] oad = new Date[];

I wasn't aware you could do this. I thought to myself "But what if I
then try to put a String into oad?" So I tried it out, and I got a runtime
ArrayStoreException. To me, this looks like a pretty ugly language design.

- Oliver
 
B

Bjorn Abelli

to show the problem I instantiate two arrays:

Object[] oad = new Date[];

I wasn't aware you could do this.

Well, not *exactly*.

You need to provide an array dimesion too.

I only wrote it hastily to show the consequences and omitted that... ;-)

But otherwise it's all according to the specs.
I thought to myself "But what if I then try to put a String into oad?"
So I tried it out, and I got a runtime ArrayStoreException. To me, this
looks
like a pretty ugly language design.

Well, I think it's actually better with that "stricter" typesafety than the
similar construction with "generic" collections. I tested the following
snippet in 1.6:

ArrayList old = new ArrayList<Date>();

old.add("foo");

?

;-)

// Bjorn A




Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
 
T

Timo Stamm

Bjorn said:
...

Well, I think it's actually better with that "stricter" typesafety than the
similar construction with "generic" collections. I tested the following
snippet in 1.6:

ArrayList old = new ArrayList<Date>();

old.add("foo");


This is not a valid comparison. The compiler warns you about the usage
of the raw type in the above code. A valid complement to

Object[] oad = new Date[];

is

ArrayList<Object> old = new ArrayList<Date>();

and this gives you an error.


Timo
 
B

Bjorn Abelli

This is not a valid comparison.

That's why I added the smiley at the end, in case anyone spotted that... ;-)
The compiler warns you about the usage of the raw type in the above code.

But my point is really that I think it's a confusing aspect that the attempt
to instantiate the ArrayList as an ArrayList<Date> is ignored and silently
"overridden" by the declared type, a "raw" ArrayList.

I would feel more comfortable if the compiler actually gave an *error* also
in that case, or at least a warning.

// Bjorn A



Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
 
M

Mike Schilling

Oliver Wong said:
Bjorn Abelli said:
to show the problem I instantiate two arrays:

Object[] oad = new Date[];

I wasn't aware you could do this. I thought to myself "But what if I
then try to put a String into oad?" So I tried it out, and I got a runtime
ArrayStoreException. To me, this looks like a pretty ugly language design.

It's a compromise. If Java had the notion of "read-only" array references,
that would be better:

Object[~write] oad = new Date[];

But imagine a Java in which

Object[] oad = new Date[];

was illegal; you couldn't use System.arraycopy().to copy things into Date
arrays, because it's declared as taking parameters that are Object arrays.
 
T

Timo Stamm

Bjorn said:
...

That's why I added the smiley at the end, in case anyone spotted that... ;-)

Sorry, I missed it :)

But my point is really that I think it's a confusing aspect that the attempt
to instantiate the ArrayList as an ArrayList<Date> is ignored and silently
"overridden" by the declared type, a "raw" ArrayList.

I would feel more comfortable if the compiler actually gave an *error* also
in that case, or at least a warning.

Yes, that would have been better.
 
M

Mike Schilling

Timo Stamm said:
Bjorn said:
...

Well, I think it's actually better with that "stricter" typesafety than
the similar construction with "generic" collections. I tested the
following snippet in 1.6:

ArrayList old = new ArrayList<Date>();

old.add("foo");


This is not a valid comparison. The compiler warns you about the usage of
the raw type in the above code. A valid complement to

Object[] oad = new Date[];

is

ArrayList<Object> old = new ArrayList<Date>();

and this gives you an error.

Generics work differently than arrays, and this is going to cause confusion
now and for the rest of Java's lifetime.


Date[] dad = newDate[12]
Object[] oad = dad;

is perfectly safe, because

oad[1] = new Object();

will cause an ArrayStoreException then and there. No data structures will
be corrupted and no subtle bugs introduced.

On the other hand

ArrayList<Date> dal = new ArrayList<Date>();
ArrayList<Object> oal = (ArrayList<Object>)dal;

is unsafe, because

oal.add(new Object());

will succeed, and only at some later time will

Date d = dal.get(12);

throw an exception, making it clear that there's been a problem *somewhere*.
 
M

Michael Powe

Mike" == Mike Schilling said:
Okay, great, that worked. What am I missing about casting
from Object to Date? I've looked at some discussions of
casting in my books but it is not clear to me -- in fact, from
my reading it would seem that it should work. (converting
object[] to date[]).

Mike> Nothing. What you're missing is that arrays (unlike generic
Mike> collections) have actual run-time types. Object[] and
Mike> Date[] are different types, just as Object and Date are, and
Mike> casting from the former to the latter can fail.

Mike> Object[] oa = new Object[1]; Date[] da = new Date[1];

Mike> Object[] oa2 = da; // allowed
Mike> Date[] da2 = (Date[])oa2; // works, since it's "really" a
Mike> Date[]
Mike> Date[] da3 = (Date[])oa; // fails at runtime with a
Mike> ClassCastException // since it's "really" an Object[]

Okay, that makes sense. I appreciate the discussion, it clarified
things for me. I actually had seen in the Sun Java forums that bad
piece of code put out as something 'that works for me' and nobody
contested it there -- and then I missed the significance in other
discussions of the .toArray( Date []) piece. The javadoc is not
clear, either.

Thanks.

mp
 
M

Mike Schilling

Okay, that makes sense. I appreciate the discussion, it clarified
things for me. I actually had seen in the Sun Java forums that bad
piece of code put out as something 'that works for me' and nobody
contested it there -- and then I missed the significance in other
discussions of the .toArray( Date []) piece. The javadoc is not
clear, either.

The javadoc says:

toArray

public Object[] toArray(Object[] a)

Returns an array containing all of the elements in this collection;
the runtime type of the returned array is that of the specified array.
If the collection fits in the specified array, it is returned therein.
Otherwise,
a new array is allocated with the runtime type of the specified array and
the
size of this collection.

That's probably clear if and only if you're already familiar with the
concept of "runtime type of an array".
 

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

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,250
Latest member
Charlesreero

Latest Threads

Top