Предупреждение об обобщениях Java, требующих медитации гуру
У меня есть некоторый Java-код, подобный следующему фрагменту (пример упрощен от исходного кода). Появится жёлтое косоглазие и предупреждающее сообщение, как указано в комментарии к коду ниже. Сообщение: "Этот вызов метода небезопасен, так как переданные аргументы могут быть неправильного типа".
abstract class Seek<T> {
abstract <S> Seek<S> seek(S... o);
abstract <T2> void map(Func<T,T2> call);
interface Func<I,O> {
public O call(I x);
}
public <X2> void go(Func<T,X2> c, T some) {
seek(some).map(c); // <- yellow squiggle here on 'c'
}
}
Почему появляется предупреждение? Каков наилучший способ исправить это?
Примечание: я использую среду разработки AIDE для Android.
РЕДАКТИРОВАТЬ: я исправил ошибку в коде после прочтения ответа от @tsolakp и @LouisWasserman.
4 ответа
На самом деле в этом коде есть три предупреждения:
Тип безопасности: потенциальное загрязнение кучи через параметр varargs o at
abstract <S> Seek<S> seek(S... o);
Параметр типа T скрывает тип T в
abstract <T,T2> void map(Func<T,T2> call);
Безопасность типов: для параметра varargs создается общий массив X1 в
seek(some).map(c);
Он может быть очищен от предупреждений A. Извлеките параметр varargs из общего вида:
abstract class Seek<T> {
abstract <S> Seek<S> seek(S o); // <- no more yellow squiggle
abstract <T1,T2> void map(Func<T1,T2> call); // <- no more yellow squiggle
interface Func<I,O> {
public O call(I x);
}
public <X1,X2> void go(Func<X1,X2> c, X1 some) {
seek(some).map(c); // <- no more yellow squiggle here on 'c'
}
}
Б. определить массивы явно как:
abstract class Seek<T> {
abstract <S> Seek<S> seek(S[] o); // <- no more yellow squiggle
abstract <T2> void map(Func<T,T2> call); // <- no more yellow squiggle
interface Func<I,O> {
public O call(I x);
}
public <X1,X2> void go(Func<X1,X2> c, X1[] some) {
seek(some).map(c); // <- no more yellow squiggle
}
}
но, S[] o
совсем не то же самое, что S... o
, Это может занять только Array явно. Может быть, вам нужно пересмотреть свой дизайн?
ИМХО: я действительно не понимаю, нужно ли иметь столько параметров типа Generic одновременно на уровне классов и методов...
map
должен иметь только T2
как параметр типа, а не T
, Сейчас T
затеняет T
от Seek<T>
класс, то есть у вас есть две переменные типа с именем T, которые на самом деле разные, и вы не хотите этого.
Предупреждения, которые я получаю от компиляции вашего кода, связаны с созданием универсального массива из seek(S...)
метод.
Если вы можете изменить это, чтобы быть List<S>
Вы можете вызвать его, используя Arrays.asList()
:
abstract class Seek<T> {
abstract <S> Seek<S> seek(List<S> o);
// ...
public <X1,X2> void go(Func<X1,X2> c, X1 some) {
seek(Arrays.asList(some)).map(c);
}
}
+ Изменить T
в T1
в map
метод. Вы также получите общее предупреждение о массиве. Вот модифицированная версия без предупреждений:
abstract static class Seek<T> {
abstract <S> Seek<S> seek(List<S> s);
abstract <T1,T2> void map(Func<T1, T2> call);
interface Func<I,O> {
public O call(I x);
}
public <X1,X2> void go(Func<X1,X2> c, X1 some) {
seek( Arrays.asList(some) ).map(c);
}
}
После некоторых комментариев выясняется, что OP, возможно, намеревался сделать map
способ быть связанным с Seek
класс универсальный тип. Если это так, мы можем использовать это решение, как предложили @Louis Wasserman и @Andy Turner:
abstract static class Seek<T> {
abstract <S> Seek<S> seek(List<S> s);
abstract <T2> void map(Func<T, T2> call);
interface Func<I,O> {
public O call(I x);
}
public <X1,X2> void go(Func<X1,X2> c, X1 some) {
seek( Arrays.asList(some) ).map(c);
}
}