Предупреждение об обобщениях 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 ответа

Решение

На самом деле в этом коде есть три предупреждения:

  1. Тип безопасности: потенциальное загрязнение кучи через параметр varargs o at abstract <S> Seek<S> seek(S... o);

  2. Параметр типа T скрывает тип T в abstract <T,T2> void map(Func<T,T2> call);

  3. Безопасность типов: для параметра 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); 
    }
}
Другие вопросы по тегам