4

Suppose a SuperClass America and two of its SubClasses SouthAmerica and NorthAmerica

Case 1

For Arrays:

America[] am = new SouthAmerica[10]; //why no compiler error
am[0]= new NorthAmerica();    //ArrayStoreException at RunTime

Case 2

While in Genrics:

ArrayList<America> ame = new ArrayList<SouthAmerica>(); //this does not compile

My question is not why case 2 does not compile but my question is why case 1 compiles.I mean what else can be do this base Array Type and Sub Array Object??

Sachin Verma
  • 3,712
  • 10
  • 41
  • 74
  • 1
    Related: http://stackoverflow.com/questions/12604477/use-of-extends-and-super-in-collection-generics/12605337#12605337 – Brian Jun 29 '13 at 19:56

4 Answers4

14

That's because arrays are covariant.

That behavior for arrays is largely considered a mistake:

String[] strings = new String[1];
Object[] objects = strings;
objects[0] = new Integer(1); // RUN-TIME FAILURE

Generic collections - being newer, fixed that mistake.

You can use bounded wildcard notation <? super America>:

ArrayList<? super America> = new ArrayList<SouthAmerica>();

This will allow you to add items to the list, but it will avoid the problematic behavior.

See this official tutorial on how to use them.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • 2
    is that mistake made by Sun for the sake of methods like Arrays.sort(any_array)?????? – Sachin Verma Jun 29 '13 at 19:53
  • @SachinVerma Java did not always have generics. Not allowing array covariance without generics would have made some tasks very tedious. Your example of `Arrays.sort` is a very good example of the sort of problem that would arise not having array covariance or generics. Now, that we have generics, this behavior is more harmful than good in the opinions of many. – Benjamin Gruenbaum Jun 29 '13 at 19:55
  • 3
    I would not call it a mistake; the fact that arrays are covariant while generic-enabled classes are not were a consequence of backwards compatibility; and this explains why you have a dedicated `.toArray()` method on lists in order to require a "type-safe" array at runtime. – fge Jun 29 '13 at 20:03
  • 3
    @fge When I wrote mistake, I meant mistake in retrospect. I believe that had Gosling built Java with generics in mind, array covariance would not have happened. Being in his position, designing a language without generics - it seems like reasonable behavior. In my previous comment to OP, I discuss why covariance is nice to have in a language without generics. This is why other languages like C# followed suit being well aware of the problematic nature, but also what it solves. – Benjamin Gruenbaum Jun 29 '13 at 20:08
  • 2
    @BenjaminGruenbaum well, .NET languages had the opportunity to learn from Java's mistakes ;) But speaking more broadly, at some point Java language desingers _will_ have to break backwards compatibility; failing that, promoting Java at some point in the future will become unsustainable. – fge Jun 29 '13 at 20:12
  • "This will allow you to *add* items to the list" - no it won't, which is the whole idea. Did you mean something else? – Paul Bellora Jun 30 '13 at 04:16
  • @PaulBellora dear god did that just sit there unnoticed for a whole day (with a link to the official tutorial explaining why it won't work, and right below an example of why it shouldn't)? THANK YOU – Benjamin Gruenbaum Jun 30 '13 at 05:03
3

You are doing something wrong. Based on what you described, suppose we have the following

public class Sample {
    public static void main() {
    America am = new SouthAmerica[10];
    }
}
class America {
    private Integer Size;
}
class NorthAmerica extends America {
    private Integer USA;
}
class SouthAmerica extends America {
    private Integer Chile;
}

I try to compile the above class and it errors out.

javac Sample.java. 
Sample.java:3: incompatible types
found   : SouthAmerica[]
required: America
America am = new SouthAmerica[10];
1 error
Deepak
  • 41
  • 3
2

Case 1: I assume you meant:

America[] am = new SouthAmerica[10]; //why no compiler error

It's valid for am to hold an array of SouthAmerica as SouthAmerica extends America.

The second line is NOT valid since the array is of SouthAmerica and you're trying to set a NorthAmerica. SouthAmerica is NOT a superclass of NorthAmerica.

The point of the first being valid is that later you can validly say:

am=new NorthAmerica[5];

This is all due to the covariance property of arrays.

Case 2: While SouthAmerica does extend America, that does not work through generics. ArrayList does NOT extend ArrayList as the implication does not hold. Generics(even though in this case it's an ArrayList) does not act in the same way as a full array.

nanofarad
  • 40,330
  • 4
  • 86
  • 117
2

Because arrays are covariant and collections are contravariant. This means that Stirng[] is Object[], but List<String> is not List<Object>. You should write the following instead:

List<? extends America> list = new ArrayList<SouthAmerica>(); 
Malcolm
  • 41,014
  • 11
  • 68
  • 91