Итак, как следует из названия, мой вопрос немного странный и сложный. Я знаю, что то, что я собираюсь сделать, нарушает все правила "хорошего" программирования, но что за жизнь, если мы немного не проживем?
Итак, я создал следующую программу. (Обратите внимание, что это было частью более крупного эксперимента, направленного на то, чтобы действительно попытаться понять дженерики, поэтому некоторые имена функций могут быть немного не в порядке)
import java.util.*;
public class GenericTestsClean
{
public static void test2()
{
BigCage<Animal> animalCage=new BigCage<Animal>();
BigCage<Dog> dogCage=new BigCage<Dog>();
dogCage.add(new Dog());
animalCage.add(new Cat());
animalCage.add(new Dog());
animalCage.printList(dogCage);
animalCage.printList(animalCage);
}
public static void main(String [] args)
{
//What will this print
System.out.println("\nTest 2");
test2();
}
}
class BigCage<T> extends Cage<T>
{
public static <U extends Dog> void printList(List<U> list)
{
System.out.println("*************"+list.getClass().toString());
for(Object obj : list)
System.out.println("BigCage: "+obj.getClass().toString());
}
}
class Cage<T> extends ArrayList<T>
{
public static void printList(List<?> list)
{
System.out.println("*************"+list.getClass().toString());
for(Object obj : list)
System.out.println("Cage: "+obj.getClass().toString());
}
}
class Animal
{
}
class Dog extends Animal
{
}
class Cat extends Animal
{
}
Теперь меня сбивает с толку то, что это хорошо компилируется с javac 1.6.0_26 , но когда я запускаю его, я получаю следующее исключение приведения класса:
Test 2
*************class BigCage
BigCage: class Dog
*************class BigCage
Exception in thread "main" java.lang.ClassCastException: Cat cannot be cast to Dog
at BigCage.printList(GenericTestsClean.java:31)
at GenericTestsClean.test2(GenericTestsClean.java:13)
at GenericTestsClean.main(GenericTestsClean.java:21)
Здесь следует отметить ряд моментов:
void printList (List >)
в классе Cage на нестатический вызывает соответствующую ошибку времени компиляции. void printList (List )
в классе BigCage на void printList (List )
выдает соответствующую ошибку. printList (List >)
в класс BigCage из class Cage , что скроет определение в классе Cage , я получаю соответствующую ошибку компилятора . Теперь, если бы мне пришлось в темноте сделать снимок того, что здесь происходит, я бы скажем, компилятор ошибается, потому что он работает в несколько этапов: Проверка типа и Разрешение перегруженного метода . На этапе проверки типа мы проходим строку с нарушением, потому что класс BigCage унаследовал void printList (List >)
от класса Cage
, который будет соответствовать любому старому списку. мы кидаем на него, поэтому уверены, что у нас есть метод, который будет работать. Однако, как только приходит время решить с помощью метода для фактического вызова, у нас возникает проблема из-за стирания типа, которое приводит к тому, что оба BigCage.printList
и Cage.printList
имеют одинаковую сигнатуру. Это означает, что когда компилятор ищет совпадение для animalCage.printList (animalCage);
, он выберет первый метод, которому он соответствует (и если мы предположим, что он начинается снизу с BigCage и выясняет, почему до Object ) сначала он найдет void printList (List )
вместо правильного совпадения void printList (List >)
Теперь для моего реального вопроса : Насколько я здесь близок к истине? Это известная ошибка? Это вообще ошибка? Я знаю, как обойти эту проблему, это скорее академический вопрос.
** EDIT **
Как мало кто написал ниже, этот код будет работать в Eclipse. Мой конкретный вопрос касается версии javac 1.6.0_26. Кроме того, я не конечно, если я полностью согласен с Eclipse в этом случае, даже если он работает, потому что добавление
printList (List >)
в BigCage приведет к приводит к ошибке времени компиляции в Eclipse, и я не вижу причины, почему он должен работать, когда один и тот же метод наследуется стихами вручную добавлено (См. Примечание 6 выше).