Если вы создаете универсальный класс в Java (класс имеет параметры универсального типа), можете ли вы использовать универсальные методы (метод принимает параметры универсального типа)?
Рассмотрим следующий пример:
public class MyClass {
public <K> K doSomething(K k){
return k;
}
}
public class MyGenericClass<T> {
public <K> K doSomething(K k){
return k;
}
public <K> List<K> makeSingletonList(K k){
return Collections.singletonList(k);
}
}
Как и следовало ожидать от универсального метода, я могу вызывать doSomething(K)
для экземпляров MyClass
с любым объектом:
MyClass clazz = new MyClass();
String string = clazz.doSomething("String");
Integer integer = clazz.doSomething(1);
Однако, если я пытаюсь использовать экземпляры MyGenericClass
без указания универсального типа, я вызываю doSomething(K)
и возвращаю Object
, независимо от того, какой K
был передан:
MyGenericClass untyped = new MyGenericClass();
// this doesn't compile - "Incompatible types. Required: String, Found: Object"
String string = untyped.doSomething("String");
Как ни странно, он будет компилироваться, если тип возвращаемого значения является универсальным классом, например. List<K>
(Собственно, это можно объяснить - см. Ответ ниже):
MyGenericClass untyped = new MyGenericClass();
List<String> list = untyped.makeSingletonList("String"); // this compiles
Кроме того, он будет компилироваться, если типизирован общий класс, даже если только с подстановочными знаками:
MyGenericClass<?> wildcard = new MyGenericClass();
String string = wildcard.doSomething("String"); // this compiles
Есть ли веская причина, по которой вызов универсального метода в нетипизированном универсальном классе не должен работать?
Есть ли какой-нибудь хитрый трюк, связанный с универсальными классами и универсальными методами, которых мне не хватает?
РЕДАКТИРОВАТЬ:
Чтобы уточнить, я ожидаю, что нетипизированный или необработанный универсальный класс не будет учитывать параметры типа универсального класса (потому что они не были предоставлены). Однако мне непонятно, почему нетипизированный или необработанный универсальный класс будет означать, что универсальные методы не соблюдаются.
Выясняется, что этот вопрос уже поднимался на SO, c.f. этот вопрос. Ответы на это объясняют, что, когда класс нетипизирован / в его необработанной форме, из класса удаляются все универсальные шаблоны, включая типизацию универсальных методов.
Однако на самом деле нет объяснения, почему это так. Итак, позвольте мне прояснить свой вопрос:
- Почему Java удаляет типизацию универсального метода в универсальных классах нетипизированного или необработанного типа? Есть ли для этого веская причина или это просто недосмотр?
РЕДАКТИРОВАТЬ - обсуждение JLS:
Было предложено (в ответ на предыдущий вопрос SO и на этот вопрос), что это рассматривается в JLS 4.8, в котором говорится:
Тип конструктора (§8.8), метода экземпляра (§8.4, §9.4) или нестатического поля (§8.3) M необработанного типа C, который не наследуется от его суперклассов или суперинтерфейсов, является исходным типом, который соответствует к стиранию его типа в универсальном объявлении, соответствующем C.
Мне ясно, как это относится к нетипизированному классу - общие типы классов заменяются типами стирания. Если универсальные шаблоны классов связаны, то этим границам соответствует тип стирания. Если они не связаны, то тип стирания - Объект, например.
// unbound class types
public class MyGenericClass<T> {
public T doSomething(T t) { return t; }
}
MyGenericClass untyped = new MyGenericClass();
Object t = untyped.doSomething("String");
// bound class types
public class MyBoundedGenericClass<T extends Number> {
public T doSomething(T t) { return t; }
}
MyBoundedGenericClass bounded = new MyBoundedGenericClass();
Object t1 = bounded.doSomething("String"); // does not compile
Number t2 = bounded.doSomething(1); // does compile
Хотя универсальные методы являются методами экземпляров, мне неясно, применяется ли JLS 4.8 к универсальным методам. Тип универсального метода (<K>
в предыдущем примере) не является нетипизированным, поскольку его тип определяется параметрами метода - только класс является нетипизированным / необработанным.