Невозможно создать статическую ссылку на универсальный подкласс (Java)
-
21-08-2019 - |
Вопрос
У меня есть следующий код:
class SuperClass {
public static String getName() { return "super"; }
}
class SubClass extends SuperClass {
public static String getName() { return "sub"; }
}
public class Dummy<T extends SuperClass> {
public void print() {
System.out.println("SuperClass: " + SuperClass.getName());
System.out.println("SubClass: " + SubClass.getName());
System.out.println("T: " + T.getName());
}
public static void main(String[] args) {
new Dummy<SubClass>().print();
}
}
Этот код выводит следующее:
SuperClass: super
SubClass: sub
T: super
Мой вопрос заключается в следующем:Почему T.getName() не возвращает значение SubClass.getName()?В конце концов, я указал, что T == подкласс.Или вызовы статических функций недопустимы для общих ссылок?
Заранее большое спасибо!
Решение
Это не просто проблема дженериков.
Если вы скажете:
SuperClass obj = new SubClass();
System.out.println(obj.getName());
вы также получите "супер".Не существует "полиморфных" статических методов.
В вашем случае все, что компилятор знает о T
заключается в том, что это расширяет SuperClass
, так что это вызовет SuperClass.getName()
.
Другие советы
В отличие от шаблонов C ++, Java generics работает со стиранием типов, поэтому генерирует только один класс для всех значений T
, и переводит все ссылки в тип T
в этом классе к супертипу T
, в данном случае SuperClass
, затем использует виртуальную отправку для обеспечения различия для вызовов методов объекта и статическую отправку для вызовов статических методов.
Поэтому, когда вы делаете Dummy<SubClass>.print()
, компилятор не производит глобальную замену T
с SubClass
в Dummy
.Все, что делает компилятор, это проверяет, что использует T
в качестве аргумента или возвращаемого типа в методах Dummy
являются SubClass
.Внутри нет никаких изменений в каком-либо коде Dummy
, так что то же самое SuperClass
статический метод вызывается как угодно T
есть.
Если вы хотите различное поведение в универсальном классе в зависимости от параметризованного типа, вы должны передать объект этого типа и использовать виртуальный метод или передать класс для этого типа и использовать отражение.
Когда вы создали экземпляр класса с помощью "new Dummy()", вы вызвали конструктор по умолчанию, который на самом деле ничего не устанавливает.Когда был вызван метод print, виртуальная машина увидела, что тип T, как указано в объявлении класса, является суперклассом;Затем он вызывает статический метод для этого класса.