I don't find any complete answer to my question to i'll do it...
After finishing the reading of SCJP book, it's a lot clearer to me. It was just treated on the generics chapter rather than arrays one. (Generics vs Arrays)
Jon Skeet answer is good but seems incomplete to me.
So you have to understand the differences with generics and arrays.
Generics are just a "compilation security". There is no check at runtime. This means, by the following trick, you CAN insert String objets into a Set
public static void main(String [] args) {
Set<Integer> set = new HashSet<Integer>();
set.add(1);
set.add(2);
addString(set,"test");
for ( Object o : (Set)set ) {
System.out.println(o);
}
for ( Object o : set ) {
System.out.println(o);
}
}
public static void addString(Set set,String s) {
set.add(s);
}
The output is:
1
2
test
1
2
ClassCastException
http://www.ideone.com/nOSQz
Note that the code compile (with a warning) and runs perfectly fine, until you use that set with a Set<Integer>
reference because there is an implicit cast that tries to cast String to Integer...
This has been done this way because of many reasons (not all exposed on the book) like retrocompatibility, and the need to be able to call legacy code (non generic), while providing non generic collections.
If you don't call any legacy code but only generics code, you should not have any problem like that, your collection contains only what you want since the compiler handled it, and there is no need to do checks at runtime...
Since generics do not have checks at runtime and try to prevent inserting the wrong item in a collection, it is forbidden to cast a List<Dog>
to a List<Animal>
, or to call a method(List<Animal>
) with a List<Dog>
param, because this would mean you could insert a Cat in a List<Dog>
by manipulating a List<Animal>
...
Arrays do not work the same.
An array have, like Jon Skeet sais, type covariance.
So we can convert a Dog[] to an Animal[] since Dog is an animal.
Like for generics, Java want to try to avoid inserting Cats to a Dog array.
But because of covariance, it can't be done at compile time.
Like Jon Skeet, i agree this covariance is perhaps not a good idea, but it's java legacy...
So, in opposition to generics, arrays do have runtime check to prevent inserting cats to a dog array.
At runtime, the JVM knows what should be inserted in my arrays, while with generics it doesn't.
So, back to my initial question
Object test = new Object[2][2];
Object[] test2 = (Object [])test;
test2[0] = "blaaa";
test2[1] = "toto";
System.out.println(test2);
test (2D array) can be casted to test2 (1D array), but behind the scene it is still a 2D array, which is finally, a 1D array A1 that expects to be filled with other 1D arrays A2's which contains Objects.
That's why an ArrayStoreException is raised when in A1 (finally test2) i try to insert a String, which is finally an Object but not an Object[]
To conclude:
There may be a little confusion because of using 1D and 2D arrays that can be casted to 1D arrays, but it would be exactly the same for this code:
Arrays:
Dog[] dogs = new Dog[1];
dogs[0] = new Dog();
Animal[] animals = (Animal [])dogs;
animals[1] = new Cat();
This fails at runtime on the 4th line.
And there is no way you can insert a cat into a dog array.
And if we do the same with generics
Set<Dog> dogs = new HashSet<Dog>();
dogs.add( new Dog() );
Set<Animal> animals = (Set<Animal>) dogs;
animals.add( new Cat() );
This doesn't compile because of the 3rd line.
But by using legacy generics code you CAN insert a cat to a dogs set.