The Artima Developer Community
Sponsored Link

Java Answers Forum
Class Conversion problem

10 replies on 1 page. Most recent reply: Oct 16, 2005 11:02 PM by Kondwani Mkandawire

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 10 replies on 1 page
KevinT

Posts: 24
Nickname: metzedler
Registered: Jun, 2003

Class Conversion problem Posted: Nov 9, 2003 6:30 PM
Reply to this message Reply
Advertisement
Well, I can cast a object b of class B to a of class A
eg: a = (A)b; (here B is the super class of A)

but why can't I cast an array of it:

(here B is the super class of A)

A[] a = new A[10];
B[] b = new B[10];
a = (A[]) b; --> this cause run time error (classCastException)

Why ?


Kishori Sharan

Posts: 211
Nickname: kishori
Registered: Feb, 2002

Re: Class Conversion problem Posted: Nov 9, 2003 8:13 PM
Reply to this message Reply
Your first example will give you runtime error too. You can always cast subclass to superclass and not vice-versa.

KevinT

Posts: 24
Nickname: metzedler
Registered: Jun, 2003

Re: Class Conversion problem Posted: Nov 10, 2003 2:55 AM
Reply to this message Reply
I don't think so, if we declare like:
B b = new A();
a superclass referrence towards a subclass
then we can still cast it back:

A a = (A)b;

but with arrays it doesn't seem we can do it can't we?

B[] b = new A[];
A[] a = (A[]) b; --> run time error + why ?

alok singh

Posts: 1
Nickname: kola99
Registered: Nov, 2003

Re: Class Conversion problem Posted: Nov 10, 2003 4:34 AM
Reply to this message Reply
> I don't think so, if we declare like:
> B b = new A();
> a superclass referrence towards a subclass
> then we can still cast it back:
>
> A a = (A)b;
>
> but with arrays it doesn't seem we can do it can't we?
>
> B[] b = new A[];
> A[] a = (A[]) b; --> run time error + why ?

The operative word in Kishori's statement was 'always'.

A[] and B[] inherit from the Array superclass (Arrays are first class object in java), and not from class A or B.

Kishori Sharan

Posts: 211
Nickname: kishori
Registered: Feb, 2002

Re: Class Conversion problem Posted: Nov 10, 2003 6:18 AM
Reply to this message Reply
Hello Mr. Kelvin
You are changing your question in every post. Your first post was not clear with your first example and that is why I gave you a generic reply. In second post you changed your second example. Anyway, here is complete explanation of your question.

1. When you cast an object reference to a particular class then Java trusts you only 50%. This means Java lets you compile the statement, but it double checks the class casting at runtime. Here is an example,

X x = (Z)y;

Here, we are trying to cast a reference variable y to type Z type. At compile time Java checks if an object of Z type is asignment compatible to an object of type X. If answer is yes then it lets you compile the code. Note that compiler doesn't check what kind of object reference variable y is referring to. It just checks for assignment compatibility between Z and X. This is so because compiler has no knowledge about the real type of object reference variable y will refer at runtime. So, compiler trusted us 50%.

However, at runtime, Java knows the actual object type reference variable y is refers to. At runtime Java will check: "Can an object of class of y be assigned to an object of class Z?". If answer is yes then it will go ahead with cast. Otherwise, it will throw classcast exception.

2. Let us discuss your problem now. A object reference of subclass can always be assigned to a refercne variable of superclas type. For example,
B b = new A();

This is fine because A is subclass. However, you cannot say,
A a = new B();
because B is super class.
In your post, you have
B b = new A();
A a = (A) b;

First statement is ok. For second statement, compiler checks if an object of type A can be assiged to an object of type A. At compile time it passes the check. At runtime, Java performs a check again. It checks the class of actual object referred to by reference variable b. Since you have assigned a reference of class A to b, runtime will find that b is referring an object of class A. Now, it will check if an object of type A ( it is b) can be assigned to an object of type A ( (A)b part of second statement). The answer is yes. So, your second statement is successful.

My reply was not the same in my first post because you din't include first statement of your first example in your post. That is why I chose to give you a generic answer.

Let us change your statement and see what happens.
B b = new B();
A a = (A) b;

compiler will be fine with second statement. At runtime, Java will find that b ( in A a = (A)b) is referring to an object of type B. However, an object of type B (superclass) is not assignment compatible to an object of type A (subclass). And, you know what happens afterwards. ClassCastException!!!

2. Let us discuss array assignment compatibility now. If you are trying to cast an array object to some other array object type then think for a moment - "Is casting ok if my objects are not array rather simple object?". If anwser comes yes then you are fine. Otherwise, Class cast execption again. So, here is an example. If you want to know if teh following statement will work
X[] x (Z[])y;


then just take out brackets and see if
X x = (Z) y;


works then array casting will also work. In case of array you are dealing with multiple element of the same kind. If something doesn't work with one element of a type then how can it work with multiple elements of the same type. In fact, for array casting the logic is same. If an object of type Y can be assigned to an object of type Z then (Z[]) y is fine when y is an array of type Y.

4. Now let us discuss your second example,

It is ok if you write
B[] b = new A[10];
A[] a = (A[]) b;


But, if you write
B[] b = new B[10];
A[] a = (A[]) b;


then it will compile, but at runtime Java will find that b is an array of type B and an object of type B cannot be assigned to an object of type A.

I hope this clears your doubt about class casting.
Thanks
Kishori

KevinT

Posts: 24
Nickname: metzedler
Registered: Jun, 2003

Re: Class Conversion problem Posted: Nov 11, 2003 3:21 AM
Reply to this message Reply
Thank u very much for the explaination, I understand that concept too. But the code below doesn't seem to conform with the rule ???

public class AddressRecord
{
private String Surname;
private String Givenname;
private String Street;
private String Suburb;
private String Postcode;
private String Telephone;
....
}

public class Header implements Manageable
{
....

public boolean store(Object data)
{
ListNode insert = head;
ListNode newNode = new ListNode(data);
newNode.next = head;
head = newNode;
}

public Object[] datadump()
{
ListNode node = head;
Object[] darray = new Object[size];
for(int i = 0; i< size; i++)
{
darray[i] = node.data;
node = node.next;
}
return darray;
}
}

public driver()
{
Manageable aRecord = new Header();
....
AddressRecord temp = new AddressRecord(s1,s2,s3);
aRecord.store(temp)
AddressRecord[] adArray = (AddressRecord[])aRecord.datadump(); //--> this will cause run time error why?
}

Kishori Sharan

Posts: 211
Nickname: kishori
Registered: Feb, 2002

Re: Class Conversion problem Posted: Nov 11, 2003 10:15 AM
Reply to this message Reply
You are getting problem because in your datadump() method you are returning an array of Object (Object[]). Since an array of object is not assignment compatible to AddressRecord type, you are getting runtime error. You can solve this in two ways.
1. In datadump() method return AddressRecord[] and not Object[]. This will solve your problem directly. You don't need any cast in driver() method. Of course, you need to change the body of datadump() method.

2. If you don't change the return type of datadump() then inside this method you can create an array of AddressRecord as
public Object[] datadump()	{
	//ListNode node = head;
	Object[] darray = new AddressRecord[size];
	//for(int i = 0; i< size; i++) {
	//	darray[i] = node.data;
	//	node = node.next;
	//}
	return darray;
}


This way the call to
aRecord.datadump();

in driver() method will return array of AddressRecord.

Kevin, at runtime the statement

(AddressRecord[])aRecord.datadump();

will succeed only if aRecord.datadump() returns an array object reference which must be assignment compatible to AdressRecord[] type. Since inside datadump() method you are creating array as:

Object[] darray = new Object[size];

and returning darray, the class cast in driver() method will always fail at runtime. darray has all elements of type AddressRecord. But, it was created as new Object[size], so its type is always Object[] and not AddressRecord[]. Another way to solve your problem is in your driver method change the code as:
Object o1 = aRecord.datadump();
		AddressRecord[] adArray = new AddressRecord[o1.length];
		for ( int i = 0; i , o1.length; i++ ) {
			if ( o1[i] instanceof AddressRecord ) {
				adArray[i] = (AddressRecord)o1[i]
			}
			
		}

KevinT

Posts: 24
Nickname: metzedler
Registered: Jun, 2003

Re: Class Conversion problem Posted: Nov 11, 2003 8:01 PM
Reply to this message Reply
Thanks for the suggestion, actually I've already tried that and it works. But maybe I'm not quick minded enough to imagine this. I just wondering : does Java "remeber" what class an instance belong to when we assigning it to some variable.
For example: when I store the data into the link list node
by writing:
aRecord.store(temp);
here temp is a AddressRecord type

(and oh ! I forgot to show you the ListNode class)

public class ListNode
{
Object data;
ListNode next;

public ListNode(Object data)
{
this.data = data;
this.next = null;
}
}

So Java has to "remember" that at certain Node it is an AddressRecord data type although it has a Object type reference is that right ?

I am quite sure about this, because I've overriden the toString() method in AddressRecord class, and I try to access it by say... current.data.toString() and that invoke the overriden method.

So when I create an array :
Object[] darray = new Object[size];
and assign each node's data field to it, it has to know the instance of object too, is that right?
So it should be ok to write

AddressRecord[] adArray = (AddressRecord[])aRecord.datadump();

Hope I am not bothering you and wasting your time.
Thanks

Kishori Sharan

Posts: 211
Nickname: kishori
Registered: Feb, 2002

Re: Class Conversion problem Posted: Nov 11, 2003 8:36 PM
Reply to this message Reply
Let us discuss little bit about object creation in Java. I am starting from very basics and at the end I will discuss your questions in last post. I hope that will clear your doubts.

When you say:

new X();

then Java allocates some memory. The actual amount of memory allocated depends on definition of class X. Memory allocated is devided in two area:
1. Header area
2. Data area

Header area is fixed in size for each object and it is implementation dependent. For example, IBM VM allocates 3 words for header for each object, whereas Sun's Hotspot VM allocates 2 words for header for each object and 3 words in case object is an array. What header area is used for? It is used for many purposes. One of them is to store the pointer to the class definition of the object. Some bits in header area are used for garbage collection purpose. Some bits in in header are used to store the length of the array object. If an object is an array then some bits are used to indicate that fact that the object is an array.

Data area is used to store the instance variable for that object.

So, given an object reference Java runtime is always able to know the class of that object using the information that it stores in its header.

When you write:

Object[] a1 = new Object[size];

then Java allocates memory for "new Object[size];" and it also stores a reference to Object class in the header area so that it can know in future that memory allocated by "new Object[size];" is for an array of Object. So, after you execute the above statement a1 starts referring to that memory area. Givem a1, Java can always tell you that a1 is referring to an array of class Object.

Suppose you write as;

Object[] a2 = new AddressRecord[size];

Here "new AddressRecord[size];" will create an array object and the header of that object will have a pointer to the class definition of AddressRecord class and not Object class. So, given a2, Java cal always tell you that it refers to an array of AddressRecord class. At runtime, Java checks the actual class of array and the declared class of array. Here, Object[] is the declared type of array a2 and AddressRecord[] is the actual type of a2.

Suppose you say,
Object[] a3 = new Object[2];

a3[0] = new AddressRecord();
a3[1] = new AddressRecord();

Now you can imagine that it is ok to store AddressRecord objects in a3[0] and a3[1]. But, the type of a3 is still Object[]. The type of array is fixed and it is fixed when you create it. Here, even though you have stored all AddressRecord objects in a3, Java is not going to change its type to AddressRecord. So when you say

AddressRecord[] a4 = (AddressRecord[])a3;

then still you get runtime error. This was your original question. Here, a3's class is Object[] and an Object is not assigned to AddressRecord. And, that is wht you get the error. However when you say;

Object[] a5 = new AddressRecord[2];
 
a5[0] = new AddressRecord();
a5[1] = new AddressRecord();
 
AddressRecord[] a6 = (AddressRecord[])a5; 


then you won't get runtime error because real type of a5 is AddressRecord[]. We just declared a5 of type Object[], but we stored a reference of AddressRecord[] in a5 and that is the final runtime type of a5.

Trevor Hatcher

Posts: 10
Nickname: newbie05
Registered: Oct, 2005

Re: Class Conversion problem Posted: Oct 16, 2005 9:31 PM
Reply to this message Reply
I receintly ran into a simlar problem: for JDK5 I made the bold changes. The new JDK allows you to specify the type of array so it will only be filled with strings ints doubles etc but not a mix. This prevents runtime errors and makes it easier sending info from one array to another because you know before sending if the arrays are compatible.
Object[] datadump() {
//ListNode node = head;
Object[] darray = new AddressRecord[size];
String Object [] darray = new AddressRecord ();
// darray = node.data;
// node = node.next;
//}
return darray

Kondwani Mkandawire

Posts: 530
Nickname: spike
Registered: Aug, 2004

Re: Class Conversion problem Posted: Oct 16, 2005 11:02 PM
Reply to this message Reply
Y are people unable to follow simple instructions, to enable
us to assist them. Format your code. Are you jokers who
are posting illegible code illeterate???!!!

Flat View: This topic has 10 replies on 1 page
Topic: Denying access to my page through programs Previous Topic   Next Topic Topic: specifying dsn as a jndi resource in jsp/struts

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use