This week's giveaway is in the Android forum.
We're giving away four copies of Android Security Essentials Live Lessons and have Godfrey Nolan on-line!
See this thread for details.
The moose likes Java in General and the fly likes Casting Object arrays to String arrays Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Casting Object arrays to String arrays" Watch "Casting Object arrays to String arrays" New topic
Author

Casting Object arrays to String arrays

Thomas Goorden
Ranch Hand

Joined: Aug 15, 2001
Posts: 39
Hi,
I'm trying to cast an array of Objects to an array of Strings (of which it was originally constructed, before being upcast).
If I iterate through the Object[], and do a getClass().getName() on each item, it shows that they are indeed all String objects.
However, when I attempt a (String[]) cast on this array, it throws a ClassCastException. Does anybody have an idea how this might happen?
Note: The upcasting is done more or less implicit (the array gets build one Object at a time, so it is never really a String[] array)
It's more like

than

the cast would be like

which only works in the second case.
Extra note:
I've hacked my way around this by making sure the original array is constructed with the same type as to which it is being cast later on. However, I'm still curious why you can't cast this kind of array, even though individually each element has the right type.
[ July 12, 2002: Message edited by: Thomas Goorden ]
[ July 12, 2002: Message edited by: Thomas Goorden ]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
If the array was created with new Object[] rather than new String[], then it really is an Object[] array, and cannot ever be cast to String[] despite the fact that each individual element is a String. You have two choices: (a) replace new Object[] with new String[] when the array is first created, or (b) sometime later, transfer the Object[] contents to a real String[] array. Sample code for the latter:


"I'm not back." - Bill Harding, Twister
Thomas Goorden
Ranch Hand

Joined: Aug 15, 2001
Posts: 39
Thanks Jim,
I had already done (+-) what you suggested, but not nearly as efficient.
Too bad that stuff like this doesn't work intuitively though...
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Drat, you modified your post while I was responding. Think of it this way - a String[] array is an Object[] array, but an Object[] array is not a String[] array. A reference variable which has been declared as type Object[] may be cast to String[], at compile time, because an Object[] reference might actually refer to a String[]. But if the actual array is of type Object[], the cast will fail at runtime. It's analogous to:

The second line compiles, since a reference to an Object might actually refer to a String, but at run time it's discovered that the Object really is, well, a plain old Object, and so an exception is thrown.
Returning to the case of the Object[] array, it doesn't matter what the contents of the array are; the array itself is an object with a class of its own, and if it doesn't obey the rules of casting, an exception is thrown.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Jim Yingst:
a String[] array is an Object[] array

Not in the formal sense of the Liskov Substitution Principle: for that you should be able to use a String[] everywhere you can use an Object[] - which obviously isn't true.
Well, just nitpicking again, I guess...


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
Umm, can you give me an actual case where you can use an Object[] but you can't use a String[] ?


Read about me at frankcarver.me ~ Raspberry Alpha Omega ~ Frank's Punchbarrel Blog
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Frank Carver:
Umm, can you give me an actual case where you can use an Object[] but you can't use a String[] ?

Yes, of course:
o[0] = new Object();
Though String is a subtype of Object, String[] is not a subtype of Object[]. Interesting, isn't it?
Also interesting that the language designers decided to make Java dynamically typed in this regard - it will compile fine and you will get a runtime error if you try.
[ July 13, 2002: Message edited by: Ilja Preuss ]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
True; a String[] doesn't really seem to be a subtype of Object[], though it's very similar to one. My analogy worked fine as far as casting is concerned, but wasn't intended to apply to all possible uses of arrays.
However, this got me thinking. Always a danger - what follows is an extended digression probably of interest to very few people other than Ilja; you have been warned. (Maybe it's not even of interest to Ilja, but hey, he started it.)
The situation seems similar to the Collection API, which offers several operations like add() and set() which are explicitly optional. Someone could write a method:

This will work fine for many Collections, but will break for others (such as a Collection returned by Collections.unmodifiableCollection()). Does this mean that an unmodifiable Collection is not a subtype of Collection? I would argue this is not a violation of the Liskov principle, because throwing an UnsupportedMethodException is valid behavior according to the API for Collection, and it's the programmer's fault if they didn't anticipate this - or at least, document the assumption that the optional method is assumed to exist for the collection, thereby passing responsibility on to whoever else uses the method, to make sure it's only called in appropriate circumstances.
I haven't read that much about the Liskov substitution principle, so I don't know if this interpretation is widely held. If not, then there are certainly other examples in Java where a subclass (in the Java sense) is not a subtype (in the Liskov sense). In fact, I don't think it would really be possible to override any method at all without violating the Liskov principle in some way. I think it only makes sense for the Liskov principle to only be applied in cases where a class is used correctly according to its own API.
In this view then, whether or not a class is really a subtype or not is determined in part by (human) interpretation of the API, which can't be verified by compiler or JVM. In this case, one could argue that the JLS does ultimately document the fact that an Object[] reference may contain an array object which is unable to contain a new Object(). ("Utimately" in the sense that it would take some doing piecing together the info from various parts of the JLS, but I'm pretty sure it's there.) And if a ClassCastException is thrown when someone tries to put an Object into a String[], that's perfectly valid behavior.
Unfortunately, it also seems as though this sort of logic could be used to justify just about any compiler or runtime error imagineable, as long as the compiler and JVM are obeying their specs. Which would tend to destroy the usefulness of the Liskov principle. So there's probably something wrong with my whole argument, but I'm not sure where exactly it is. What's the proper cutoff between an exception which is a normal part of a method's documented behavior, and an exception which demonstrates a violation of the Liskov principle?
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
Jin wrote: What's the proper cutoff between an exception which is a normal part of a method's documented behavior, and an exception which demonstrates a violation of the Liskov principle?
Presumably in Java the cutoff is the one between checked and unchecked exceptions. A subject about which there has been a lot of discussion.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Jim Yingst:
True; a String[] doesn't really seem to be a subtype of Object[], though it's very similar to one. My analogy worked fine as far as casting is concerned, but wasn't intended to apply to all possible uses of arrays.

Yes, of course - as I said, I was only nitpicking...

However, this got me thinking.


Always a danger - what follows is an extended digression probably of interest to very few people other than Ilja; you have been warned. (Maybe it's not even of interest to Ilja, but hey, he started it.)

Hah! I really love this types of discussions!

The situation seems similar to the Collection API, which offers several operations like add() and set() which are explicitly optional. Someone could write a method:

This will work fine for many Collections, but will break for others (such as a Collection returned by Collections.unmodifiableCollection()). Does this mean that an unmodifiable Collection is not a subtype of Collection?

As far as I understand it does mean exactly that! In fact you could make the point that a modifiable Collection is a subtype of a similar unmodifiable Collection.
Recently there was a discussion on news:comp.object about a similar subject.
I would argue this is not a violation of the Liskov principle, because throwing an UnsupportedMethodException is valid behavior according to the API for Collection, and it's the programmer's fault if they didn't anticipate this - or at least, document the assumption that the optional method is assumed to exist for the collection, thereby passing responsibility on to whoever else uses the method, to make sure it's only called in appropriate circumstances.

Well, the LSP defines subtypes by behaviour, not by conformance to an interface. To be a subtype, for every instance of the supertype there should be an instance of the subtype, so that substituting the instances the behaviour of the system doesn't change. Of course, it all comes down to what you define as "behaviour"...

I haven't read that much about the Liskov substitution principle, so I don't know if this interpretation is widely held.

I don't think this is a widely held interpretation. OTOH there is in fact some confusion about the LSP; and there are some rather prominent voices questioning the value of the LSP.
See http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple
If not, then there are certainly other examples in Java where a subclass (in the Java sense) is not a subtype (in the Liskov sense).

Yes - in fact subclassing and subtyping are more or less orthogonal concepts.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Casting Object arrays to String arrays
 
Similar Threads
Interface
An object to hold several arrays
Casting and Interfaces
Strange 'var arg' method.
Object References in JAVA. (Coming from C++)