• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

casting an object array

 
Nick Delauney
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello all,
Im trying to cast an Object array and I'm getting a runtime ClassCastException error. I don't see why I cant cast an array of Objects into an array of Strings, considering String extends Object.
here is a snippet:
// converting from a list to an Array of Objects
Object comparableObjectsArray[] = aList.toArray();
quicksort((String[])comparableObjectsArray);
Your help is appreciated.
[ April 22, 2003: Message edited by: Nick Delauney ]
 
Joel McNary
Bartender
Posts: 1840
Eclipse IDE Java Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
While it is true that String extends Object, it would not be true to say that String[] extends Object[]. Because arrays are objects in Java, conceptually String[] and Object[] extend the class "[]" (some sort of generic array class). We don't have access to this class (it would be VM-specific, anyway...) and we really don't care to have access to that class. We could do Really Stupid Things (TM) if we did.
So, in short, arrays simply don't work that way.
 
Joel McNary
Bartender
Posts: 1840
Eclipse IDE Java Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
BTW, looking at your code, you should be able to write your quicksort method to take an Object[] as a parameter and cast the objects to java.lang.Comperable objects as you work with them (or build a Comperable[] as the first step in quicksort, if you didn't want to do all that casting).
This way, your quicksort method could handle any of the primitive wrapper classes, Strings, and any other class that implements the Comperable interface.
You just have to trap for ClassCastExceptions in case your method is passed an array consiting of, say, java.sql.DriverManager objects or java.lang.NullPointerException objects.
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I agree with Joel that it's probably preferable to write quicksort() to take an Object[] (or even the original List) rather than Object[]. Or for that matter, what's wrong with Arrays.sort() and Collections.sort()? But maybe this is an assignment, or there's some other reason not to use existing sort() methods.
Anyway, to the original question:
aList.toArray() creates an Object[]. A String[] would be a subtype of Object[] - that is, a String[] can be treated as an Object[] but an Object[] cannot be treated as a String[]. Once toArray() returns something that is really an Object[], there is simply no way to call it a String[].
However, IF all the objects inside aList are indeed String objects, then there is a way you could put the aList contents in a String[] rather than an Object[]:

The overloaded toArray(Object[]) method allows us to put the aList contents inside an already-created array, rather than creating a new Object[] array. Because the array was already created using new String[], it's really a String[] (even though it can be treated as an Object[]).
There's another way to write this which accomplishes much the same thing, in a slightly different fashion:

Here we take advantage of the fact that toArray() is written so that if the array argument is to small for the collection contents to fit, toArray() instead creates an entirely new array of the same type as the array that was used as an argument. Thus "new String[0]" creates a zero-size arry whose only purpose is to tell the toArray() method what type the "real" array should have. Personally I never liked this technique as it seems a bit convoluted, but it turns out to require only one line rather than the two lines of my preferred method above (not counting the quicksort) - so many people prefer this second method.
[ April 22, 2003: Message edited by: Jim Yingst ]
 
Nick Delauney
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank You Jim and Joel, I used Jim's first method and it made everything work. This was very informative.
thanks again.
 
Xu Song
Greenhorn
Posts: 20
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi all,
The solution is obviously correct:Using the overloaded toArray(Object[]).But I still cannot understand your explanation.
Check Chapter5.4 of the Java Language Specification v2.0:That's the casting conversion rules.Since the elements of new array and the old one are legal to cast(Object can be casted to String),there's no error in the compile-time.In run-time,even if the aList is added with String elements,the ClassCastException still prompted.I'm confused by this runtime exception actually.
Your comments would be appreciated very much.
regards
xusoo
 
Dirk Schreckmann
Sheriff
Posts: 7023
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'd like to take this rare opportunity to nitpick Jim's post a bit.
----
While Jim's suggestion to use
String[] strings = aList.toArray(new String[0]);
is a good idea, the syntax isn't correct, and this won't compile.
The result of the call to toArray is a reference of type Object[]. This still needs to be cast to a String[] type reference.
String[] strings = (String[])aList.toArray(new String[0]);
----
And another thing: I'd guess that when Jim said, "I agree with Joel that it's probably preferable to write quicksort() to take an Object[] (or even the original List) rather than Object[]." he actually meant, "I agree with Joel that it's probably preferable to write quicksort() to take a Comparable[] (or even the original List) rather than Object[]."
----
OK, I won't go into any typos...
 
Dirk Schreckmann
Sheriff
Posts: 7023
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Xu Song:
The solution is obviously correct:Using the overloaded toArray(Object[]).But I still cannot understand your explanation.
Check Chapter5.4 of the Java Language Specification v2.0:That's the casting conversion rules.Since the elements of new array and the old one are legal to cast(Object can be casted to String),there's no error in the compile-time.In run-time,even if the aList is added with String elements,the ClassCastException still prompted.I'm confused by this runtime exception actually.

Ah, I guess you're upset that the following code results in a ClassCastException at runtime.

Perhaps the bit to understand here is that an Object[] is not a String[], even if the Object[] only contains String components. So, a String[] type reference cannot be used to refer to an Object[].
Remember that casting doesn't change the type of an object, it's just a mechanism for creating a reference of a different type than the reference being cast, which refers to the same object.
So, just casting a reference of type Object[], which refers to an Object[] object, to a reference of type String[] doesn't create a new String[] object, and thus the ClassCastException.
If it's still just not clear, let me suggest a reading of some of the JavaRanch Campfire Stories - especially the "Cup Size", "Pass-by-Value Please", and "How my Dog learned Polymorphism" stories. And of course, ask as many questions around here as you like until you "get it".
 
Dirk Schreckmann
Sheriff
Posts: 7023
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Joel McNary:
While it is true that String extends Object, it would not be true to say that String[] extends Object[].

Actually the String[] type does extend the Object[] type.

The result is true. So, a String[] is an Object[].
If this were not true, then Jim's toArray method wouldn't work as it does. Remember it takes an Object[] type reference as an argument, and it returns an Object[] type reference, but the argument is allowed to be a reference of type String[] (or any other object type array), and the returned value can be cast to a String[] (or any other object type array).
The gist of the initial misunderstanding of this thread is that the converse of the above example is not true - Object[] is not a String[]. In other words, an object of the parent type is not necessarily an object of the child type. (An animal is not necessarily a dog - it might be a cat.)

The result is false.
 
Xu Song
Greenhorn
Posts: 20
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Dirk,
Check the following codes:
___________________________________________
code 1)
public class Foo{
public static void main(String[] args) {
Object[] objects = new Object[2];
objects[0] = "one";
objects[1] = "two";
String[] strings = (String[])objects;
}
}
___________________________________________
code 2)
public class Foo{
public static void main(String[] args) {
Object object = new Object();
object = "one";
String string = (String)object;
}
}
___________________________________________
The code 1) has a ClassCastException at runtime.But the code 2) results in no exception at runtime.In this case,The casting conversion does not work with Object array only.Do I understand correctly?
But array is also a kind of Object,why the casting conversion works on all kinds of object,only except for array?
I know a little about 'Pass by value/reference',Polymorphism.Otherwise it's a shame since I just passed SCJP several months ago.
But frankly,the campfire stories is very funny and helpful,and the 'remote controller'(object reference) impress me strongly.Thanks a lot for your recommendation reading.
xusoo
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24211
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Xu Song:

The code 1) has a ClassCastException at runtime.But the code 2) results in no exception at runtime.In this case,The casting conversion does not work with Object array only.Do I understand correctly?

In (1), you have a reference to an Object whose concrete type is Ob ject[]. You try to cast it to a String[], and get an error. You can't change the type of an object using a cast; you can only change the type being used to refer to it.
In (2), you've got an Object variable pointing to a String object. You can cast to a String because the object really is a String. That's the big difference. A cast never changes the type of an object.
Incidentally, it's widely considered that having String[] be a subclass of Object[] was a design flaw in Java. Watch this:

Line (1) is legal because you can assign a subclass object to a superclass variable without a cast. Line 2, although it compiles, gets an ArrayStoreException at runtime, as you can't put an Object into a String[]! This violates the Liskov Subtitution Principle, which is widely held to be part of the definition of proper polymorphic behavior. The Principle states that anything you can do to a superclass object, you can do to any subclass object; you can see that it doesn't hold in this case.
 
Dirk Schreckmann
Sheriff
Posts: 7023
 
Xu Song
Greenhorn
Posts: 20
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi all,
The short conclusion for me:array is special.
In code 2),the 'object' variable pointing to a string object.So the casting is correct since the 'object' really is a String after the statement:
object="one".
In code 1),although all elements of the 'objects' variable are pointing to Strings after the statements,the 'objects' variable is still an object array.The casting is correct if and only if the 'objects' variable is defined as a String[].
Your comments is welcome.
xusoo
 
Dirk Schreckmann
Sheriff
Posts: 7023
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think you're almost there Xu Song.
The short conclusion for me:array is special.
I'm not sure about what you mean. In some ways arrays are special. But in many ways, especially those concerning some of the data types concerns discussed in this thread, they aren't special - they're just objects with a type and a defined inheritance relationship.
In code 2),the 'object' variable pointing to a string object.So the casting is correct since the 'object' really is a String after the statement: object="one".
Right.
In code 1),although all elements of the 'objects' variable are pointing to Strings after the statements,the 'objects' variable is still an object array. The casting is correct if and only if the 'objects' variable is defined as a String[].
No, not quite. If you were to amend your statement to say, "The casting is correct if and only if the object referenced by the 'objects' variable is defined as a String[]," then you'd be correct.
In other words, the following code is ok from a compile-time and runtime type perspective.
 
Xu Song
Greenhorn
Posts: 20
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
exactly,Dirk.I agree with your correction.
xusoo
 
Dirk Schreckmann
Sheriff
Posts: 7023
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Good. Then you're likely understanding the concepts.
 
Maulin Vasavada
Ranch Hand
Posts: 1873
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi all,
I guess we missed one important point here.
In the following snippet,
Object o = new Object(); // Line 1
o = "maulin"; // Line 2
String s = (String)o;
Across ine 1 and Line 2 we are "changing" the reference to which 'o' refers. When we do new Object() 'o' get some reference and when we do o = "maulin" it get "new" reference to a string "maulin"; We are not doing o.setValue("maulin") sort of thing basically if you know what I mean...
Well, rest of the arguments/explanation are fine but I thought we should keep this behavior in mind...
Regards
Maulin
 
Dirk Schreckmann
Sheriff
Posts: 7023
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic