2009-03-24 3 views
5

я следующий код:Невозможно сделать статическую ссылку на общий подкласс (Java)

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 == SubClass. Или вызовы статической функции недействительны для общих ссылок?

Большое спасибо!

ответ

13

Это не просто проблема с дженериками.

Если вы говорите:

SuperClass obj = new SubClass(); 
System.out.println(obj.getName()); 

вы также получите "супер". Нет «полиморфных» статических методов.

В вашем случае все, что компилятор знает о T, состоит в том, что он расширяет SuperClass, поэтому он назовет SuperClass.getName().

+0

Хорошо, это ясно до сих пор. Но как я могу затем вызвать статический метод SubClass.getName() из Dummy с помощью T? Я хотел бы иметь много дополнительных подклассов, в которых Dummy может вызывать getName() прозрачно. – JeffreyHammansson

0

Когда вы инициировали класс с помощью «нового Dummy()», вы вызывали конструктор по умолчанию, который на самом деле ничего не устанавливает. Когда метод печати получил вызов, VM увидела, что тип T, объявленный в объявлении класса, является SuperClass; Затем он вызывает статический метод в этом классе.

1

В отличие от шаблонов C++, Java дженериков работы по типу стирания, так что это только порождает один класс для всех значений T, и переводит все ссылки на тип T в этом классе супер типа T, в этом случае SuperClass, то использует виртуальную диспетчеризацию для предоставления дисперсии для вызовов методам объектов и статической отправки на вызовы статическим методам.

Так что, когда вы делаете Dummy<SubClass>.print(), компилятор не делает глобальную замену из T с SubClass в Dummy. Весь компилятор делает проверку, что использование T в качестве аргумента или типа возврата в методах Dummy: SubClass. Никакого изменения кода внутри Dummy нет, поэтому тот же самый статический метод SuperClass называется так, как T.

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

Смежные вопросы