Расширение общих классов
public class MyGeneric<T, E> {}
public class Extend1<T, E> extends MyGeneric<T, E> {}
public class Extend2 extends MyGeneric<String, Object> {}
Насколько мне известно, оба подкласса в приведенном выше примере действительны. Мне было интересно, как Java знает, когда типы, заданные в суперклассе, будут определены при создании экземпляра подкласса и когда они являются фактическими именами классов (т.е. Как он знает, что T, E не являются именами классов)?
Замечание, допустимо ли (даже необычно) использовать более одной буквы для общих типов? Что делать, если (через некоторую отрывочную ошибку планирования) Типы конфликтуют с существующим классом, например.
public class E{}
public class Foo<E>{}
что происходит потом?
Изменить: Спасибо, что ответили так быстро.
Чтобы ответить на мой первый вопрос, Ответ Joachim является наиболее эффективным.
Чтобы ответить на боковую точку, ответ на aioobe более ясный
Ответы
Ответ 1
Посмотрите на это определение:
public class Extend1<T, E> extends MyGeneric<T, E> {}
Здесь T
и E
присутствуют дважды и в двух разных ролях
- в
Extend1<T,E>
вы определяете аргументы типа. Это означает, что тип Extend1
имеет два (неограниченных) типа аргумента T
и E
. Этот сообщает компилятору Java, что те, кто использует Extend1
, должны указывать типы.
- в
extends MyGeneric<T,E>
вы используете ранее определенные аргументы типа. Если T
и E
не были известны как аргументы типа здесь, то T
и E
будут простыми типами ссылок, то есть компилятор будет искать классы (или интерфейсы,...) с именем T
и E
(и, скорее всего, не найдут их).
Да, аргументы типа следуют тем же синтаксическим правилам, что и любой другой идентификатор в Java, поэтому вы можете использовать несколько букв ABC
или даже имена, которые могут вводить в заблуждение (использование аргумента типа String
является законным, но высокий запутанный).
Имена аргументов однобуквенного типа - это очень обычная стратегия именования.
Ответ 2
Мне было интересно, как Java знает, когда типы, заданные в суперклассе, будут определены, когда подкласс инициализируется, и когда они являются фактическими именами классов (т.е. как он знает T, E не являются именами классов )?
Java все равно. Если вы...
class MyGeneric<String> extends ArrayList<String> {
String value;
}
допустимо (хотя и необычно) использовать более одной буквы для общих типов? Что делать, если (через некоторую потерю ошибки планирования) Типы конфликтуют с существующим классом, например.
Да, вы можете использовать любой допустимый идентификатор Java для параметров типа.
Имена могут быть конфликтующими, но Java не будет рассматривать это как ошибку. Идентификаторы между <
... >
всегда будут рассматриваться как параметры типа, независимо от того, соответствует ли идентификатор имени класса.
Это может быть довольно запутанным. Вот пример:
class MyGeneric<String> extends java.util.ArrayList<String> {
String value;
}
class Test {
public static void main(String... args) throws Exception {
MyGeneric<Integer> obj = new MyGeneric<Integer>();
obj.value = 5;
// ^
// |
// '--- Assign an integer to what seems to be a String!
}
}
Аналогичный вопрос:
Ответ 3
Нет проблем с:
public class E{}
public class Foo<E>{}
Поскольку в контексте Foo<E>
, E
является типом.