Решение для предупреждения компилятора для обобщенных varargs - PullRequest
5 голосов
/ 21 ноября 2011

Загадка из этого блога .Аналогично SO1445233 .

. Учитывая следующий список источников, объясните, почему компилятор выдает предупреждение при вызове метода list, и дайте решение для удаления предупреждения, не прибегая к аннотации @SuppressWarnings..

public class JavaLanguagePuzzle3 {
  public static void main(String[] args) {
    list("1", 2, new BigDecimal("3.5"));
  }  
  private static <T> List<T> list(T... items) {
    return Arrays.asList(items);
  }
}

Предупреждение:

Type safety: A generic array of Object&Serializable&Comparable<?> is created for a varargs parameter

Ответы [ 5 ]

3 голосов
/ 01 декабря 2012

Измените тело main с list("1", 2, new BigDecimal("3.5")); на JavaLanguagePuzzle3.<Object>list("1", 2, new BigDecimal("3.5"));

Причина: синтаксис <> указывает, какую версию универсального метода вы хотите.Но вам нужно поставить . перед ним, чтобы сделать синтаксический анализатор счастливым, и имя класса до этого по той же причине.

Источник: http://codeidol.com/java/javagenerics/Introduction/Generic-Methods-and-Varargs/

2 голосов
/ 21 ноября 2011

Вот мои мысли.

public static interface Foo extends Serializable, Comparable<Object> {
}

public static void main(String[] args) {
  // Problem: Unsafe: varargs has generic type
  implicitList("1", 2, BigDecimal.valueOf(3.5)); // warning: generic vararg

  // Solution 1: Constrain type of varags explicitly through generics
  explicitList1(Object.class, "1", 2, BigDecimal.valueOf(3.5));
  // However, we could still have the same error from problem
  explicitList1(Foo.class, "1", 2, BigDecimal.valueOf(3.5)); // warning: generic vararg
  // Fix: Make containing class to exact type (PECS) an array is both producer and consumer
  explicitList2(Foo.class, "1", 2, BigDecimal.valueOf(3.5)); // error: incompatible args

  // Solution 2: Override varargs by passing array
  implicitList(new Object[] { "1", 2, BigDecimal.valueOf(3.5) });
}

private static <T> List<T> explicitList1(Class<? extends T> klass, T... items) {
  return Arrays.asList(items);
}

private static <T> List<T> explicitList2(Class<T> klass, T... items) {
  return Arrays.asList(items);
}

private static <T> List<T> implicitList(T... items) {
  return Arrays.asList(items);
}
1 голос
/ 21 ноября 2011

Я задал вопрос по этому вопросу некоторое время назад.
Проблема: учитывая заголовок метода <T extends List<?>> void foo(T... args) Вы можете хранить не-T значения в сгенерированном массиве (небезопасное поведение). (Смотрите мой вопрос ниже для более подробной информации)
Решение: В Java 7 они добавили аннотацию @SafeVarargs, которую вы можете включить в свой метод для подавления этого предупреждения.

Упрощенный вызов метода Varargs в Java 7

0 голосов
/ 21 ноября 2011

Сообщение об ошибке на самом деле немного вводит в заблуждение. Проблема здесь не в том, что аргумент типа является общим, а в том, что это тип пересечения. Только один тип элемента этого типа пересечения может быть повторно определен как тип компонента массива. Таким образом, хранение объектов в этом массиве, которые реализуют некоторые другие типы элементов типа пересечения, не вызовет ArrayStoreException:

public class Example {
    interface A {}
    interface B {}
    interface C {}

    static class X implements A, B {}
    static class Y implements A, B, C {}

    public static void main(String[] args) {
        // inferred type: A&B, erased down to A resulting in a A[]
        bar(new X(), new Y());
    }

    static <T> void bar(T... ts) {
        Object[] os = ts;
        os[0] = new A() {}; // should fail, does not => warning
        os[0] = new B() {}; // fails as expected
    }
}
0 голосов
/ 21 ноября 2011

Сообщение вызвано тем, что в качестве аргументов для list существует смесь типов, и правильная привязка для параметра типа T не очевидна.Одно из исправлений (не в духе безопасности типов) заключается в удалении генериков:

private static List<Object> list(Object... items) {
    return Arrays.asList(items);
}
...