How do you cast to array?

D

DeMarcus

Look at this.

Vector v = new Vector();
v.add( new String( "Nothing" ) );
String[] sv = (String[])v.toArray();

Why do I get a ClassCastException here?

Thanks
Daniel
 
J

Joona I Palaste

DeMarcus said:
Look at this.
Vector v = new Vector();
v.add( new String( "Nothing" ) );
String[] sv = (String[])v.toArray();
Why do I get a ClassCastException here?

Because what you get is an Object[], and String[] and Object[] aren't
compatible types. If they were, you could have an Object[] reference
referring to a String[] object, and use this to set one of the
elements to refer to some other type of object than String - major
bummer.
The toArray() method has a different version taking one array
parameter. It employs some compiler magic (which I'm not altogether
familiar with) to make the returned object the same array class as
the parameter. You only need an array - it doesn't have to contain
anything. I usually do this:

String[] sv = (String[])v.toArray(new String[0]);
 
M

Michael Borgwardt

DeMarcus said:
Look at this.

Vector v = new Vector();
v.add( new String( "Nothing" ) );
String[] sv = (String[])v.toArray();

Why do I get a ClassCastException here?

Because the parameterless toArray() method returns an object of type
object[], which could, just like Vector, hold all kinds of objects.

You want the toArray() method that takes a parameter, then it will
return an object of the type you give as paramter (and throw a
ClassCastException of the Vector contains any other types).
 
G

guest

String[] sv = (String[])v.toArray(new String[0]);


That is stupidly inefficient. Use:
String[] sv = (String[])v.toArray(new String[v.size()]);
 
D

Daniel Chirillo

I don't know enough about the internals to give you a complete answer.
I'll let someone else provide more details.

Here's what I've noticed: Although the compiler will allow you to
downcast arrays, you will always get a ClassCassException if you
downcast an array. Note that you will not get a ClassCassException if
you cast an individual element in an array; only if you cast the entire
array.

Vector's toArray() returns an array of Objects. Even though you know
that there are only Strings in the Vector, you can't downcast the array
that toArray() is returning.

Here is the proper way to do what you are trying to do:

Vector v = new Vector();
v.add( new String( "Nothing" ) );
String[] sv = ( String[] )v.toArray( new String[ v.size() ] );
 
?

=?ISO-8859-1?Q?Daniel_Sj=F6blom?=

Joona said:
It employs some compiler magic (which I'm not altogether
familiar with) to make the returned object the same array class as
the parameter.

Not compiler magic, but reflection magic:

Array.newInstance(array.getClass().getComponentType(), size);
 
D

DeMarcus

Joona said:
DeMarcus said:
Look at this.

Vector v = new Vector();
v.add( new String( "Nothing" ) );
String[] sv = (String[])v.toArray();

Why do I get a ClassCastException here?


Because what you get is an Object[], and String[] and Object[] aren't
compatible types. If they were, you could have an Object[] reference
referring to a String[] object, and use this to set one of the
elements to refer to some other type of object than String - major
bummer.
The toArray() method has a different version taking one array
parameter. It employs some compiler magic (which I'm not altogether
familiar with) to make the returned object the same array class as
the parameter. You only need an array - it doesn't have to contain
anything. I usually do this:

String[] sv = (String[])v.toArray(new String[0]);

Thanks Joona.
One can wonder who on earth have use for the toArray() I tried to use.
 
D

DeMarcus

Michael said:
DeMarcus said:
Look at this.

Vector v = new Vector();
v.add( new String( "Nothing" ) );
String[] sv = (String[])v.toArray();

Why do I get a ClassCastException here?


Because the parameterless toArray() method returns an object of type
object[], which could, just like Vector, hold all kinds of objects.

You want the toArray() method that takes a parameter, then it will
return an object of the type you give as paramter (and throw a
ClassCastException of the Vector contains any other types).

Thanks Michael.
 
J

Joona I Palaste

guest said:
String[] sv = (String[])v.toArray(new String[0]);
That is stupidly inefficient. Use:
String[] sv = (String[])v.toArray(new String[v.size()]);

I was under the impression that only the class of the object being
passed to toArray() mattered. Do you have a JLS citation or test results
to prove this, or are you simply guessing?

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-------------------------------------------------------- rules! --------/
"The obvious mathematical breakthrough would be development of an easy way to
factor large prime numbers."
- Bill Gates
 
M

Michael Borgwardt

Joona said:
String[] sv = (String[])v.toArray(new String[0]);
That is stupidly inefficient. Use:
String[] sv = (String[])v.toArray(new String[v.size()]);

I was under the impression that only the class of the object being
passed to toArray() mattered. Do you have a JLS citation or test results
to prove this, or are you simply guessing?

How about the API doc for the method:

Parameters:
a - the array into which the elements of this list are to be stored, if it is big
enough; otherwise, a new array of the same runtime type is allocated for this purpose.


However, I wouldn't call it "stupidly inefficient" either - in most cases it
makes so little difference that it's not worth wasting a thought on.
 
J

Joona I Palaste

Michael Borgwardt said:
Joona said:
String[] sv = (String[])v.toArray(new String[0]);
That is stupidly inefficient. Use:
String[] sv = (String[])v.toArray(new String[v.size()]);

I was under the impression that only the class of the object being
passed to toArray() mattered. Do you have a JLS citation or test results
to prove this, or are you simply guessing?
How about the API doc for the method:
Parameters:
a - the array into which the elements of this list are to be stored, if it is big
enough; otherwise, a new array of the same runtime type is allocated for this purpose.

Thanks. Serves me right.
However, I wouldn't call it "stupidly inefficient" either - in most cases it
makes so little difference that it's not worth wasting a thought on.

Right you are. I just tried both ways with a list of one hundred
thousand elements, repeated ten thousand times. Guess how much using
the array passed in saved me in contrast to constructing a new array?
About 0.34%. IOW, one three-hundredth. Not worth losing sleep over.
 
C

Chris Uppal

Joona said:
Right you are. I just tried both ways with a list of one hundred
thousand elements, repeated ten thousand times. Guess how much using
the array passed in saved me in contrast to constructing a new array?
About 0.34%. IOW, one three-hundredth. Not worth losing sleep over.

Since the array of size 100K is going to be allocated (and intialised) anyway,
however you express it, the real difference is in the allocation, or not, of
the 0-sized array. The allocation (and intialisation) of a 0-sized array is
"obviously" going to be tiny in comparison with a 100K array. If you want the
difference to show up better, compare the case where the input has only 1 or 2
elements. (Not that I can imagine a context where the difference /would/ make
a difference, but at least you'd get a bigger percentage number from your tests
;-)

-- chris
 
J

Joona I Palaste

Since the array of size 100K is going to be allocated (and intialised) anyway,
however you express it, the real difference is in the allocation, or not, of
the 0-sized array. The allocation (and intialisation) of a 0-sized array is
"obviously" going to be tiny in comparison with a 100K array. If you want the
difference to show up better, compare the case where the input has only 1 or 2
elements. (Not that I can imagine a context where the difference /would/ make
a difference, but at least you'd get a bigger percentage number from your tests
;-)

A test using a list of one element, repeated one million times, showed
using the array passed in was a little over four times as fast as
constructing a new array. So it's apparently mostly a question of how
big arrays you're using.
 
J

John C. Bollinger

DeMarcus said:
One can wonder who on earth have use for the toArray() I tried to use.

One can only wonder who has use for the Vector class you tried to use.
Or other implementations of the List interface. Or any implementation
of Set. None of these (prior to 1.5) supported element types more
specific than Object. If you can deal with the Collection types at all
then their no-arg toArray() methods' return type is just par for the course.


John Bollinger
(e-mail address removed)
 
X

xarax

DeMarcus said:
Look at this.

Vector v = new Vector();
v.add( new String( "Nothing" ) );
String[] sv = (String[])v.toArray();

Why do I get a ClassCastException here?

Vector.toArray() returns Object[].


Use this instead:
{
String[] sv;
Vector v;
String s;
int kk;

v = new Vector();
s = "Nothing";
v.add(s);
/* add more String instances here */


kk = v.size();
sv = new String[kk];
v.toArray(sv);
}

Hope this helps.
 
X

xarax

Daniel Chirillo said:
I don't know enough about the internals to give you a complete answer.
I'll let someone else provide more details.

Here's what I've noticed: Although the compiler will allow you to
downcast arrays, you will always get a ClassCassException if you
downcast an array.
/snip/

Wrong.

{
String[] sa;
Object[] oa;

sa = new String[1];
sa[0] = "Fubar";
oa = (Object[]) sa; /* upcast OK */
sa = (String[]) oa; /* downcast OK */
}

That's an example that won't get ClassCastException.
The actual component type of the array when the array
was created determines how far down you can cast an
Object[].

If you created an Object[], then you're stuck with
that. If you created a String[], then you can cast
back-and-forth between Object[] and String[].

You cannot cast downward any deeper than the
original array element type that was specified
when the array was created. It doesn't matter
whether the actual instances in the array have
deeper sub-types or whether they could all be
downcast successfully to a deeper sub-type.

public class A {}
public class B extends A {}

{
B[] ba;
A[] aa;

aa = new A[1];
aa[0] = new B(); /* sub-type of A */
ba = (B[]) aa; /* downcast: ClassCastException */
}

The ClassCastException above occurs due to
the array element type is A, not B, even
though every element instance of the array
is type B.

This is all specified in the JLS. An array has
its own type and its own rules for downcasting
that are separate from the rules for downcasting
the individual element instances.

Hope this helps.
 
J

Joona I Palaste

xarax said:
Daniel Chirillo said:
I don't know enough about the internals to give you a complete answer.
I'll let someone else provide more details.

Here's what I've noticed: Although the compiler will allow you to
downcast arrays, you will always get a ClassCassException if you
downcast an array. /snip/

{
String[] sa;
Object[] oa;
sa = new String[1];
sa[0] = "Fubar";
oa = (Object[]) sa; /* upcast OK */
sa = (String[]) oa; /* downcast OK */
}
That's an example that won't get ClassCastException.
The actual component type of the array when the array
was created determines how far down you can cast an
Object[].

I figure trying to do
oa[0] = new Integer(1);
will then throw an ArrayStoreException.
 
X

xarax

Joona I Palaste said:
xarax said:
Daniel Chirillo said:
I don't know enough about the internals to give you a complete answer.
I'll let someone else provide more details.

Here's what I've noticed: Although the compiler will allow you to
downcast arrays, you will always get a ClassCassException if you
downcast an array. /snip/

{
String[] sa;
Object[] oa;
sa = new String[1];
sa[0] = "Fubar";
oa = (Object[]) sa; /* upcast OK */
sa = (String[]) oa; /* downcast OK */
}
That's an example that won't get ClassCastException.
The actual component type of the array when the array
was created determines how far down you can cast an
Object[].

I figure trying to do
oa[0] = new Integer(1);
will then throw an ArrayStoreException.

Yes, the assignment must be compatible with the
underlying array element type. The JavaDoc for
ArrayStoreException has your example.
 
N

NOBODY

constructing a new array. So it's apparently mostly a question of how
big arrays you're using.

Common guys, one uses reflection to figure the array type, the other one is
direct compiled code, plus, you get the chance to cache the array for
reuse.

That is the good old same optimization that the one in swing
getSize(Dimension d) so that you can avoid 'new'.


(I cannot believe the % of coders forgetting that 'new' is expensive...)
 
M

Michael Borgwardt

NOBODY said:
That is the good old same optimization that the one in swing
getSize(Dimension d) so that you can avoid 'new'.


(I cannot believe the % of coders forgetting that 'new' is expensive...)

And I cannot believe the number of people still believing this. It's a thing
of the past. Nowadays, object creation is highly optimized and very fast in
most cases.
 

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,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top