Java, привязка статических методов и универсальные шаблоны объединены с некоторой перегрузкой метода

Итак, как следует из названия, мой вопрос немного странный и сложный. Я знаю, что то, что я собираюсь сделать, нарушает все правила "хорошего" программирования, но что за жизнь, если мы немного не проживем?

Итак, я создал следующую программу. (Обратите внимание, что это было частью более крупного эксперимента, направленного на то, чтобы действительно попытаться понять дженерики, поэтому некоторые имена функций могут быть немного не в порядке)

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)

Здесь следует отметить ряд моментов:

  1. Два printList НЕ переопределяют, а перегружают друг друга, как ожидалось (у них есть различных типов, потому что общие типы их аргументов различны). Это можно проверить с помощью аннотации @Override
  2. . Изменение метода void printList (List ) в классе Cage на нестатический вызывает соответствующую ошибку времени компиляции.
  3. Изменение метода void printList (List ) в классе BigCage на void printList (List ) выдает соответствующую ошибку.
  4. В main () вызов printList () через класс BigCage (т.е. BigCage.printList (...)) генерирует ту же ошибку времени выполнения
  5. В main () вызов printList () через класс Cage (то есть Cage.printList (...)) работает должным образом, только вызывая версию из printList в Cage
  6. Если я скопирую определение для 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 выше).

9
задан Bob9630 10 October 2019 в 01:44
поделиться