Is a MyClass[] also an Object[]?

A

Andrea Desole

This is something someone just told me after discussing the
implementation of methods working with arrays.
Now, I have a few questions:
is it true?
If it's true, can I also say that Derived[] is also a Base[]?
Any reference available?
Thanks

Andrea
 
T

Tor Iver Wilhelmsen

Andrea Desole said:
is it true?

No. Both MyClass[] and Object[] are objects of their own "class" which
directly extends java.lang.Object. They are not related.
 
B

Bob

Andrea said:
This is something someone just told me after discussing the
implementation of methods working with arrays.
Now, I have a few questions:
is it true?
If it's true, can I also say that Derived[] is also a Base[]?


If you mean: can you assign an array of type Derived to an array
reference variable declared as type Base, then yes you can.

class Base {}
class Derived extends Base {}

Base[] baseArray;
Derived[] derivedArray = new Derived[x];
baseArray = derivedArray;

(Despite what I said a few posts ago, when confused.)

Also, given the above, both the following expressions are true:

(derivedArray instanceof Object)
(baseArray instanceof Object)

as arrays are always objects.
 
A

Andrea Desole

Bob said:
Andrea said:
If it's true, can I also say that Derived[] is also a Base[]?



If you mean: can you assign an array of type Derived to an array
reference variable declared as type Base, then yes you can.

class Base {}
class Derived extends Base {}

Base[] baseArray;
Derived[] derivedArray = new Derived[x];
baseArray = derivedArray;

(Despite what I said a few posts ago, when confused.)

so if I have the following methods:

void foo( Base[] bases )
void bar( Object[] objects )

I can call:

foo( derivedArray )
bar( derivedArray )
bar( baseArray )

Is there a place where I can find it? Is it in the language
specification somewhere?
 
B

Bob

Andrea said:
so if I have the following methods:

void foo( Base[] bases )
void bar( Object[] objects )

I can call:

foo( derivedArray )
bar( derivedArray )
bar( baseArray )


Yes. But to be certain I'm not giving you false information (and because
I've got too much time on my hands), I wrote and compiled the following
code:

/* BEGIN CODE EXAMPLE */
class Base {}

class Derived extends Base {}

public class TestArrayPolymorphism {
public static void main(String [] args) {
Base [] baseArray = new Base[4];
Derived [] derivedArray = new Derived[4];

foo(derivedArray);
bar(derivedArray);
bar(baseArray);

System.out.println("Finished.");
}

public static void foo(Base [] bArray) {
System.out.println("foo called with argument " + bArray);
}

public static void bar(Object [] oArray) {
System.out.println("bar called with argument " + oArray);
}
}
/* END CODE EXAMPLE */


The code compiled without error, and running it gives the following output.

foo called with argument [LDerived;@1add2dd
bar called with argument [LDerived;@1add2dd
bar called with argument [LBase;@eee36c
Finished.


However, (and this is what I was thinking of a few posts ago when I was
confused) you CANNOT assume the same is true for primitive arrays. For
example, you cannot assign a byte array to a reference variable declared
to be an int[] array, even though you are permitted to store a byte
value in an int variable. (You can still store a byte into an *element*
of an int array, e.g. intArray[0] = byteValue.)
Is there a place where I can find it? Is it in the language
specification somewhere?

To be honest, I'm not sure. I only know because I taught myself with a
book that trains you for the SCJP exam.

Let me see... a quick search turned up the Java Language Specification

http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html#27805

The Sun Java Tutorials don't seem to mention this in their array
section, so the Java Language Specification is probably your best resource.
 
J

John C. Bollinger

Tor said:
is it true?


No. Both MyClass[] and Object[] are objects of their own "class" which
directly extends java.lang.Object. They are not related.

That is technically correct, but not at all the whole story. Java
specifies that there is a "widening reference conversion" "From any
array type SC[] to any array type TC[], provided that SC and TC are
reference types and there is a widening conversion from SC to TC." (JLS
2e, 5.1.4). Widening reference conversions are among those that are
allowed in assignments, method invocations, and casts, and hence are
also accounted for by the instanceof operator and the methods of class
Class that examine assignment compatibility. Therefore, although the
class corresponding to MyClass[] is not a subclass of that corresponding
to Object[], Java behaves in almost every way as if it were. In
particular, the following is completely legal Java (barring any simple
typos):

class MyClass {}

public class Main {
void method(Object[] oa) {}

public static void main(String[] args) {
MyClass[] myArray = new MyClass[0];

// assign a MyClass[] reference to a variable of type Object[]:
Object[] objArray = myArray;

/*
* pass a MyClass[] reference to a method argument of type
* Object[]
*/
method(myArray);

/*
* A MyClass[] reference passes an "instanceof Object[]" test
*/
if (myArray instanceof Object[]) {
// Will be printed:
System.out.println("All your base are belong to us");
}
}
}


John Bollinger
(e-mail address removed)
 
C

Chris Smith

Tor Iver Wilhelmsen said:
Andrea Desole said:
is it true?

No. Both MyClass[] and Object[] are objects of their own "class" which
directly extends java.lang.Object. They are not related.

I think you'll find that, as kludgy as it is, MyClass[] does indeed
extend Object[]. See the API docs for java.lang.ArrayStoreException as
well.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Uppal

Andrea said:
I specially found interesting par.
10.10, which makes me think such an easy conversion between Base[] and
Derived[] shouldn't maybe be allowed, because it implies a possible
inconsistent behaviour

The main problems with the way that a Derived[] is allowed to be used where a
Base[] is expected are that:

a) Using
aBaseArray[3] = aBaseInstance;
will require a runtime check, unless the runtime JITer can prove to itself that
the object referred to by "aBaseArray" is not in fact an instance of Dervied[]
(or, I suppose, if it could prove that "aBaseInstance" is not in fact a
Derived. I've never seen any claims that any JVM implementation actually does
that kind of proof, and you would normally assume that all array /writes/
require a type check (as well as a bounds check).

b) The write to an array can in fact fail at runtime -- i.e. its a hole in the
type system.

c) The notion of assignability (and the isAssignableFrom() methods) don't
follow the actual class hierarchy as closely as you'd expect.

-- chris
 
A

Andrea Desole

Chris said:
c) The notion of assignability (and the isAssignableFrom() methods) don't
follow the actual class hierarchy as closely as you'd expect.

I think this is what I mean. If I have a method that takes a Base[] I
would expect, in that method, the possibility to replace an element in
that array. And this is indeed possible if I give to my method a Base[].
But if I give a Derived[] this is not possible anymore. This is quite
inconsistent.
 
B

Bob

Andrea said:
Bob said:
Let me see... a quick search turned up the Java Language Specification

http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html#27805

thank you, this was interesting. I specially found interesting par.
10.10, which makes me think such an easy conversion between Base[] and
Derived[] shouldn't maybe be allowed, because it implies a possible
inconsistent behaviour

That is an interesting point, and something I wasn't aware of. And I
agree that it could cause problems. Any method that takes an object
array and updates its contents could fall foul of this incompatibility,
unless the reference type was marked as final.
 
J

John C. Bollinger

Chris said:
I think you'll find that, as kludgy as it is, MyClass[] does indeed
extend Object[]. See the API docs for java.lang.ArrayStoreException as
well.

Nope. From JLS 2e, section 10.8: "The direct superclass of an array
type is Object." See my response to Tor, however.


John Bollinger
(e-mail address removed)
 
J

John C. Bollinger

Andrea said:
Chris said:
c) The notion of assignability (and the isAssignableFrom() methods)
don't
follow the actual class hierarchy as closely as you'd expect.


I think this is what I mean. If I have a method that takes a Base[] I
would expect, in that method, the possibility to replace an element in
that array. And this is indeed possible if I give to my method a Base[].
But if I give a Derived[] this is not possible anymore. This is quite
inconsistent.

Your argument is sound. I think this is an area where the Java
designers compromised OO principles to provide for easier use, but the
cost is as you describe. All in all, I think I'll accept this
particular compromise -- I have certainly made use of the language
feature to my advantage, but I have rarely seen an ArrayStoreException.
Knowing about this is half the battle, and carefully documenting
method behavior is the other half.


John Bollinger
(e-mail address removed)
 
C

Chris Smith

John C. Bollinger said:
Chris said:
I think you'll find that, as kludgy as it is, MyClass[] does indeed
extend Object[]. See the API docs for java.lang.ArrayStoreException as
well.

Nope. From JLS 2e, section 10.8: "The direct superclass of an array
type is Object." See my response to Tor, however.

Hmm. Learn something new every day.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Smith

Bob said:
That is an interesting point, and something I wasn't aware of. And I
agree that it could cause problems. Any method that takes an object
array and updates its contents could fall foul of this incompatibility,
unless the reference type was marked as final.

It's interesting to contrast this to the generics spec in Java 1.5.
Arrays are, after all, merely a special case of the general idea of
generic types.

In generics, List<MyClass> is *not* related to List<Object> in any way.
However, there are extensions to data types that define new rules for
their compatibility with certain values... for example, there is the
type List<? super MyClass>, which is a reference type that can point to
objects of class List<MyClass> or List<Object>. There is also
List<? extends MyClass>, which can point to objects of List<MyClass> and
List<DerivedClass>, where DerivedClass extends MyClass. Certain
operations of List (for example, add) can't be performed with a
List<? extends MyClass> reference, and other operations (for example,
get) are restricted to work with the Object class when called on a
List<? super MyClass> reference.

The trade-off is clear. The case with generics above is somewhat
complex; perhaps too complex for a large base of people adjusting to
Java before it was an established language. On the other hand, arrays
create a fault in type safety. The choice of which is desirable is, in
the end, up for grabs. We do know which way Sun is moving, though.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
B

Bob

John said:
Your argument is sound. I think this is an area where the Java
designers compromised OO principles to provide for easier use, but the
cost is as you describe. All in all, I think I'll accept this
particular compromise -- I have certainly made use of the language
feature to my advantage, but I have rarely seen an ArrayStoreException.
Knowing about this is half the battle, and carefully documenting method
behavior is the other half.

I would think that one answer would be to create a method in the
following way, to be safe:

Base[] methodName(Base[] argArray) {
Base [] newArray = new Base[argArray.length];

for (int i = 0; i < argArray.length; ++i) {
newArray = argArray;
}

// Perform operations on newArray

return newArray;
}


Perhaps not the most efficient way of doing things, but at least you
would avoid trying to illegally modify any arrays that were a subclass type.
 
C

Chris Uppal

John said:
I think this is an area where the Java
designers compromised OO principles to provide for easier use, but the
cost is as you describe. All in all, I think I'll accept this
particular compromise -- I have certainly made use of the language
feature to my advantage, but I have rarely seen an ArrayStoreException.

I've /never/ seen one (caused by this issue), not ever.

So I think the Java designers were right to ditch static type soundness (which
is /not/ part of "OO principles", IMO) to allow greater flexibility. There's
no doubt that its an ugly wart in the system, but I don't think it does much
harm in reality, and there's no way to "fix" the type system without
introducing a great deal of unwanted complexity (can you spell "generics" ? ;-)

-- chris
 
M

Mike Schilling

Your argument is sound. I think this is an area where the Java designers
compromised OO principles to provide for easier use, but the cost is as
you describe. All in all, I think I'll accept this particular
compromise -- I have certainly made use of the language feature to my
advantage, but I have rarely seen an ArrayStoreException.


Nor have I. Without this feature, it would have been impossible to write
many of the useful methods in the Arrays class that take generic Object[]
parameters until 1.5.
 

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

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top