aspose file tools*
The moose likes Beginning Java and the fly likes casting an object array Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "casting an object array" Watch "casting an object array" New topic
Author

casting an object array

Nick Delauney
Ranch Hand

Joined: Sep 28, 2002
Posts: 43
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 ]

N.D:"Anything worth having, takes time to get"
Joel McNary
Bartender

Joined: Aug 20, 2001
Posts: 1824

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.


Piscis Babelis est parvus, flavus, et hiridicus, et est probabiliter insolitissima raritas in toto mundo.
Joel McNary
Bartender

Joined: Aug 20, 2001
Posts: 1824

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

Joined: Jan 30, 2000
Posts: 18671
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 ]

"I'm not back." - Bill Harding, Twister
Nick Delauney
Ranch Hand

Joined: Sep 28, 2002
Posts: 43
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

Joined: Nov 16, 2001
Posts: 20
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

Joined: Dec 10, 2001
Posts: 7023
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...


[How To Ask Good Questions] [JavaRanch FAQ Wiki] [JavaRanch Radio]
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
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

Joined: Dec 10, 2001
Posts: 7023
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

Joined: Nov 16, 2001
Posts: 20
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

Joined: Jul 08, 2003
Posts: 24187
    
  34

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.


[Jess in Action][AskingGoodQuestions]
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
Liskov Schmiskov
Xu Song
Greenhorn

Joined: Nov 16, 2001
Posts: 20
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

Joined: Dec 10, 2001
Posts: 7023
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

Joined: Nov 16, 2001
Posts: 20
exactly,Dirk.I agree with your correction.
xusoo
Dirk Schreckmann
Sheriff

Joined: Dec 10, 2001
Posts: 7023
Good. Then you're likely understanding the concepts.
Maulin Vasavada
Ranch Hand

Joined: Nov 04, 2001
Posts: 1873
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

Joined: Dec 10, 2001
Posts: 7023
Huh?
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: casting an object array