Почему необработанные типы в одном месте заставляют родовые призывы в другом месте рассматриваться как сырые?
Рассмотрим следующий пример:
import java.util.*;
class Foo<T> {
public int baz(List<String> stringlist) { return 1; }
public int baz(ArrayList<Object> objectlist) { return 2; }
public static void main(String[] args) {
Foo<String> foo = new Foo<String>(); // (A)
//Foo foo = new Foo(); // (B)
System.out.println(foo.baz(new ArrayList<String>()));
}
}
Почему он печатает 1
в (A)
, но 2
с (B)
?
Я знаю, как работает разрешение метода, поэтому мне не нужно объяснять это мне.
Я хочу узнать более глубокую мотивацию этой "функции".
Почему в этом нет предупреждения о стирании? (Существует только один о Foo foo = new Foo()
.)
Почему разрешение метода использует стираемую семантику, хотя задан общий тип?
Ответы
Ответ 1
Это потому, что, когда компилятор разрешает перегрузки, он рассматривает каждый метод как общий или не общий, ни один из двух, поэтому кандидаты:
-
Foo<T>.baz(List<String>)
-
Foo<T>.baz(ArrayList<Object>)
если foo
является Foo<String>
, или
-
Foo.baz(List)
-
Foo.baz(ArrayList)
если foo
является foo
.
Нет такой вещи, как Foo.baz(List<String>)
. Рассматриваются либо все параметры типа, либо нет. (Я не знаю, что это явно указано в JLS, но имеет смысл с тех пор, как обрабатывать общий метод, как если бы это был исходный эквивалент, это функция обратной совместимости.)
В первом случае Foo<T>.baz(List<String>)
соответствует, но Foo<T>.baz(ArrayList<Object>)
не работает.
Во втором случае обе функции соответствуют, а Foo.baz(ArrayList)
- более конкретный, поэтому он выбран.
Ответ 2
Он даже не будет компилировать регистр (A), если вы сохраняете только один метод baz(ArrayList<Object>)
(метод error: нельзя применить к заданному типу).
Я думаю, ArrayList<String>
не является подклассом ArrayList<Object>
.
Странно, что он компилируется в случае (B), но они, должно быть, приняли некоторые странные решения, чтобы сохранить обратную совместимость с коллекциями с не общим набором.