Я не нахожу полного ответа на мой вопрос, потому что я сделаю это ...
После прочтения книги SCJP мне стало намного понятнее.Это было рассмотрено только в главе об обобщениях, а не в массивах.(Generics vs Arrays) Ответ Джона Скита хорош, но мне кажется неполным.
Так что вы должны понимать разницу с универсальными и массивами.
Дженерики - это просто "безопасность компиляции".Там нет проверки во время выполнения.Это означает, что с помощью следующего трюка вы МОЖЕТЕ вставить строковые объекты в набор
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);
}
Выход:
1
2
test
1
2
ClassCastException
http://www.ideone.com/nOSQz
Обратите внимание, чтокод компилируется (с предупреждением) и работает отлично, пока вы не используете этот набор со ссылкой Set<Integer>
, потому что существует неявное приведение, которое пытается привести String к Integer ...
Это было сделаноЭто объясняется многими причинами (не все раскрыты в книге), такими как ретро-совместимость и необходимость иметь возможность вызывать устаревший код (не универсальный), в то же время предоставляя не универсальные коллекции.
Если вы не вызываете какие-либоУнаследованный код, но только обобщенный код, у вас не должно быть таких проблем, ваша коллекция содержит только то, что вы хотите, так как компилятор ее обработал, и нет необходимости делать проверки во время выполнения ...
Поскольку обобщенные элементыне проверять во время выполнения и пытаться предотвратить вставку неправильного элемента в коллекцию, запрещено приводить List<Dog>
к List<Animal>
или вызывать method(List<Animal>
) с параметром List<Dog>
, bпотому что это может означать, что вы можете вставить Cat в List<Dog>
, манипулируя List<Animal>
...
Массивы не работают одинаково.
Массив имеет, например,Jon Skeet sais, введите covariance.
Таким образом, мы можем преобразовать Dog [] в Animal [], так как Dog - животное.
Как и в случае с дженериками, Java хочет попытаться избежать вставки Catsк массиву собак.Но из-за ковариации это не может быть сделано во время компиляции.Как и Джон Скит, я согласен, что эта ковариация, возможно, не очень хорошая идея, но это наследие Java ... Так что, в отличие от генериков, массивы действительно имеют проверку во время выполнения, чтобы предотвратить вставку кошек в массив собак.
ВВо время выполнения JVM знает, что должно быть вставлено в мои массивы, в то время как с генериками это не так.
Итак, вернемся к моему первоначальному вопросу
Object test = new Object[2][2];
Object[] test2 = (Object [])test;
test2[0] = "blaaa";
test2[1] = "toto";
System.out.println(test2);
test (2D array) можно преобразовать в test2 (массив 1D), но за сценой это все еще двумерный массив, который, наконец, является одномерным массивом A1, который, как ожидается, будет заполнен другими одномерными массивами A2, которые содержат объекты.
Вот почему возникает ArrayStoreException, когда в A1 (наконец, test2) я пытаюсь вставить строку, которая, наконец, является объектом, но не объектом []
В заключение:
Тамможет быть небольшая путаница из-за использования 1D и 2D-массивов, которые могут быть преобразованы в 1D-массивы, но это будет точно так же для этого кода:
Массивы:
Dog[] dogs = new Dog[1];
dogs[0] = new Dog();
Animal[] animals = (Animal [])dogs;
animals[1] = new Cat();
Это не удаетсяво время выполнения на 4-й линии.И вы никак не можете вставить кошку в массив собак.
И если мы сделаем то же самое с генериками
Set<Dog> dogs = new HashSet<Dog>();
dogs.add( new Dog() );
Set<Animal> animals = (Set<Animal>) dogs;
animals.add( new Cat() );
Это не скомпилируется из-за 3-й строки.Но с помощью устаревшего универсального кода вы МОЖЕТЕ вставить кошку в набор собак.