Crazy Java Error of the Day (CJED)

0 views
Skip to first unread message

Adam Parkin

unread,
May 15, 2009, 11:42:37 AM5/15/09
to Recreational Computer Science Society
Hello all, was reading a paper on why Java is a terrible choice for a
first programming language in a CS1 class, and came across this little
tidbit of code that I thought I'd share with the rest of the
class. :p Some of you have likely seen it before, but just because
bashing Java's fun (tee-hee) I thought I'd pass it along nonetheless.

Okay say we have a class with some methods & attributes:

public class A {
.....
}

Which is of course fine, but now as a CS1 instructor we want to show
students inheritance so we derive a subclass from A:

public class B extends A {
......
}

Which of course has it's own stuff that's unique to B, as well as all
the stuff from A. Now let's write the following code, and see if you
can spot the error:

public static void main (String [] args)
{
A [] aS = new A[10]; // an array of 10 A's
B [] bS = new B[10]; // an array of 10 B's

bS[0] = new B(); // let's create a new B to put at the start of
the array

aS = bS; // valid since all B's are A's
aS[1] = new A(); // and let's create a new A object for the 2nd
slot
}

Did you spot the error? Nope, it's not the line that assigns an array
of subtypes to an array of supertypes (or not exactly). It's actually
the line that immediately follows that line that creates a new A
instance and puts it into an array of A's. If you compile the above
you'll get an ArrayStoreException at runtime. The paper I saw this in
called this the "covariance problem".

I'm not entirely sure of the reason for this, I think it is because
when you assign an array to another array it doesn't do a deep copy of
the two arrays, but rather at that point each array is a reference to
the same array in memory. I tried to confirm this hypothesis with the
following code:

bS[0] = new B();
bS[0].x = 42; // assuming A has a public member
called "x"
aS = bS;
aS[0] = new B();
aS[0].x = 113;
bS[0].display();

Which causes 113 to be displayed indicating that aS and bS are both
references to the same array. Since bS was defined as an array of
B's, and you can't assign an A instance to an array of B's (rightfully
so), once you do the "aS = bS;" line the type of aS changes to be an
array of B's rather than an array of A's. Kind of a neat way of
breaking Java's type system if you think about it.

At any rate, imagine being a 1st year CS student and you run into
this. Then you go to your instructor who has to somehow explain in a
meaningful yet simple way why an instance of A can't be in an array of
A's. :p

For those interested, the paper I saw this in can be found at:

http://www.springerlink.com/content/uefgvqflaxvudy1e/

And is a rather entertaining read.

Adam

PS - just for completeness sake, here's the entire Java source that I
wrote in playing around with this:

public class Test
{
public class A
{
public int x;

void display ()
{
System.out.println ("A display");
}
}

public class B extends A
{
void display ()
{
System.out.println ("B display " + x);
}
}


public static void main(String[] args)
{
new Test().runMe();
}

public void runMe()
{
A [] aS = new A[10];
B [] bS = new B[10];

bS[0] = new B();
bS[0].x = 42;

aS = bS;

aS[0].display();
aS[0] = new B();
aS[0].x = 113;
bS[0].display();

aS[1] = new A(); // causes an ArrayStoreException
}
}

Noel Burton-Krahn

unread,
May 15, 2009, 12:22:53 PM5/15/09
to recco...@googlegroups.com
Interesting. I guess I can see how this would happen internally,
since a B[] can be downcast to an A[], but a B[] will only accept B
values.

A[] aa = new B[3];
aa[0] = new A(); // throws ArrayStoreException

I tried to generate a similar error with Java's typed lists, but
couldn't fool Java into generating run-time errors. This won't
compile, as you would expect:

List<A> la = new ArrayList<B>();

~Noel
Reply all
Reply to author
Forward
0 new messages