casting Object[] to String[] - why not?

M

Marteno Rodia

Hello,
I encountered another problem today... I have an ArrayList<String> to
which I put String tokens. This takes place in a method which is to
return an array of these String tokens after parsing the input String
has been finished. Last line in the method:

return (String[]) tokenList.toArray();

throws: java.lang.ClassCastException: [Ljava.lang.Object; cannot be
cast to [Ljava.lang.String;

Why can't I do that? I've been putting only Strings to the ArrayList,
and the only reason why I must cast is that the standard toArray()
method returns array of Objects (not Strings)... And I have no idea
why the exception is thrown.
 
D

Donkey Hottie

Hello,
I encountered another problem today... I have an ArrayList<String> to
which I put String tokens. This takes place in a method which is to
return an array of these String tokens after parsing the input String
has been finished. Last line in the method:

return (String[]) tokenList.toArray();

throws: java.lang.ClassCastException: [Ljava.lang.Object; cannot be
cast to [Ljava.lang.String;

Why can't I do that? I've been putting only Strings to the ArrayList,
and the only reason why I must cast is that the standard toArray()
method returns array of Objects (not Strings)... And I have no idea
why the exception is thrown.

try

return tokenList.toArray(new String[tokenList.size()]) ;
 
M

Marteno Rodia

I appreciate all your suggestions, however,
return tokenList.toArray(new String[tokenList.size()]) ;
is the shortest and the most comfortable one.
Moreove, it works!

Thanks,
MR
 
L

Lew

I appreciate all your suggestions, however,
return tokenList.toArray(new String[tokenList.size()]) ;

is the shortest and the most comfortable one.
Moreove, it works!

It's not the shortest, actually.

return tokenList.toArray(new String [0])

is shorter.

BTW, putting "List" in the name of the list is somewhat bad practice.
 
K

Karl Uppiano

Lew said:
I appreciate all your suggestions, however,
return tokenList.toArray(new String[tokenList.size()]) ;

is the shortest and the most comfortable one.
Moreove, it works!

It's not the shortest, actually.

return tokenList.toArray(new String [0])

is shorter.

BTW, putting "List" in the name of the list is somewhat bad practice.

I am curious; I tend to use the form:

tokens.toArray(new String[tokens.size()]);

thinking that passing in an appropriately sized array would eliminate the
need to reallocate memory for the array, as it seems would be necessary when
sending in a zero length array. Am I wasting my time (and possibly memory
and processor cycles, when I thought I was saving both)?

Regards,
Karl
 
A

Arne Vajhøj

Karl said:
Lew said:
I appreciate all your suggestions, however,
return tokenList.toArray(new String[tokenList.size()]) ;

is the shortest and the most comfortable one.
Moreove, it works!

It's not the shortest, actually.

return tokenList.toArray(new String [0])

is shorter.

BTW, putting "List" in the name of the list is somewhat bad practice.

I am curious; I tend to use the form:

tokens.toArray(new String[tokens.size()]);

thinking that passing in an appropriately sized array would eliminate
the need to reallocate memory for the array, as it seems would be
necessary when sending in a zero length array. Am I wasting my time (and
possibly memory and processor cycles, when I thought I was saving both)?

No.

toArray checks on the length and if it is too short then it allocates
a new array.

So Lew is "wasting" the allocation of an empty array, so your code
may be a few nanoseconds faster than his. Which most likely does
not matter at all.

I quickly checked some code of mine - I use your way 75% and Lew's 25%.

Arne
 
L

Lew

Karl said:
I am curious; I tend to use the form:

tokens.toArray(new String[tokens.size()]);

thinking that passing in an appropriately sized array would eliminate
the need to reallocate memory for the array, as it seems would be
necessary when sending in a zero length array. Am I wasting my time
(and possibly memory and processor cycles, when I thought I was saving
both)?

Patricia said:
For most lists, I don't think it matters much. It should not take much
time to allocate a zero element array that immediately becomes unreachable.

If the List is subject to access from multiple threads, the zero length
array approach works provided toArray is synchronized. The size()
based form needs additional synchronization to ensure there is no change
in the size of the List between the size call and the toArray call.

Thomas Pornin's approach:
2. use a "template" array to give the type information to the list,
and let it create the array of the proper size itself:

// somewhere in the class
private static final String[] STRING_ARRAY_TEMPLATE = new String[0];
// ...

String[] e = l.toArray(STRING_ARRAY_TEMPLATE);

essentially eliminates the overhead of allocation of the zero-length array,
the more so the more times one uses 'toArray()' in scope of the static final.

(I am not fond of lower-case "ell" as a variable name.)

Looking at the source, 'ArrayList.toArray()' lacks synchronization but
'Collections.SynchronizedCollection' synchronizes both forms of the method on
its internal 'mutex'.
 
E

Eric Sosman

Patricia said:
K
I am curious; I tend to use the form:

tokens.toArray(new String[tokens.size()]);

thinking that passing in an appropriately sized array would eliminate
the need to reallocate memory for the array, as it seems would be
necessary when sending in a zero length array. Am I wasting my time
(and possibly memory and processor cycles, when I thought I was saving
both)?

For most lists, I don't think it matters much. It should not take much
time to allocate a zero element array that immediately becomes unreachable.

There's a little more expense than creating and collecting
away the zero-length array. If the passed array is too short,
the implementation has to use reflection to discover its run-time
element type and to instantiate a new array of sufficient size.
Reflective operations have a reputation for being noticeably more
expensive than non-reflective alternatives. (ArrayList was the
only concrete implementation I actually checked, but I cannot
imagine how any other could allocate an array of "Same type as
him over there, but bigger" without resorting to reflection.)

But as you say, it probably doesn't make a huge difference.
If the List is subject to access from multiple threads, the zero length
array approach works provided toArray is synchronized. The the size()
based form needs additional synchronization to ensure there is no change
in the size of the List between the size call and the toArray call.

Looks like a wash to me: The synchronization must be done in
any case, whether by the List implementation or by the user. At
worst, the penalty ought to be a couple of recursive acquisitions
of a lock already held.
 
S

Stefan Ram

Marteno Rodia said:
return (String[]) tokenList.toArray();
Why can't I do that? I've been putting only Strings to the ArrayList,

The expression type »java.lang.String[]« of an expression »e«
gives a guarantee to the compiler that, when »i« is a valid
index, »e[ i ]« will be »null« or an object of class »java.lang.String«.

The compiler cannot prove that this is the case here based on
the type of the expression »tokenList.toArray();«.
The compiler can not take the types of objects into account,
because objects exist not earlier than at run time. They do
not exist at compile time, so the compiler can not see them.

A smart compiler could do an »abstract interpretation« of the
source code, to see this sometimes, but still the rules of
Java are specified not to require a compiler to do this, and
therefore request the behavior you observe.
 
A

Andreas Leitgeb

Eric Sosman said:
Looks like a wash to me: The synchronization must be done in
any case, whether by the List implementation or by the user. At
worst, the penalty ought to be a couple of recursive acquisitions
of a lock already held.

Is synchronisation for toArray(...) any way different from any other list-
accessor? I think toArray shouldn't need any more synchronisation than if
it is used in an addAll() of another List. The quoted texts read to me as
if there were some extra need. (If I misread, please just say so)

All involved arrays are either thread-local, or used read-only - except
for when the user passes a globally accessible non-zero-sized array,
that happens to be just large enough for the list, but then he hopefully
knows what he's doing.
 
A

Andreas Leitgeb

Patricia Shanahan said:
Andreas said:
Is synchronisation for toArray(...) any way different from any other list-
accessor?
The issue I was talking about was
someList.toArray(new String[someList.size()])

Yes, it occurred to me about 5 seconds after posting, that it was
about two separate accessors ;-} I then cancelled my post, but
you were either faster or my cancel didn't work on your site.

Btw., while wondering how arrays are recreated for type, I looked at the
byte code of Array.copyOf(), and it indeed uses reflection, too (getClass
on the old one, and java.lang.reflect.Array.newInstance(...)).

What surprised me in the byte code of that method is, that it does a
checkcast (for "[Ljava/lang/Object;") twice immediately subsequently.
checkcast places the checked reference back on the stack, so the second
one sure looks redundant to me.

I look at byte code rather often, and haven't yet seen that anywhere
else, so far. In the source of Arrays.copyOf I also don't see anything
that would explain a redundant double-cast to me.

PS: No, I'm not implying performance problems from that; I'm just curious.
 
L

Lew

Andreas said:
Yes, it occurred to me about 5 seconds after posting, that it was
about two separate accessors ;-} I then cancelled my post, but
you were either faster or my cancel didn't work on your site.

Nor mine. Nor most people's. Perhaps not anyone's. Cancels generally don't
work.
 
L

Lars Enderin

Lew said:
Nor mine. Nor most people's. Perhaps not anyone's. Cancels generally
don't work.
It seems to have worked with my news provider. I can't see the post
Patricia responded to.
 
L

Lew

Lars said:
It seems to have worked with my news provider. I can't see the post
Patricia responded to.

There have been times when I've tried to cancel a post just after making it
and it disappears from my newsreader, but then I got a slew of responses from
others who could still see it.

Oddly, I am unable to see some posts I've recently made to clj.programmer that
I've made no effort to cancel. Go figure.

I figure now that there's no way for me to avoid embarrassing myself if I make
a silly post, and that I just won't understand when or if cancels happen.
 
K

Karl Uppiano

Lew said:
There have been times when I've tried to cancel a post just after making
it and it disappears from my newsreader, but then I got a slew of
responses from others who could still see it.

Oddly, I am unable to see some posts I've recently made to clj.programmer
that I've made no effort to cancel. Go figure.

I figure now that there's no way for me to avoid embarrassing myself if I
make a silly post, and that I just won't understand when or if cancels
happen.

I have never had cancels work very well when a newsgroup spans several news
servers. The caching and persistence probably varies by manufacturer, as
well as how everything propagates over the net. The only time it has really
worked for me is when the NG is on a single server such as an intranet
server or maybe places like grc.com.
 

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

Latest Threads

Top