Java Arrays vs Generics

2020-07-23 03:42发布

问题:

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??

回答1:

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.



回答2:

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


回答3:

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.



回答4:

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>();