Можно ли решить, что предупреждение компилятора «Общий массив T создан для параметра varargs»? - PullRequest
146 голосов
/ 18 сентября 2009

Это упрощенная версия рассматриваемого кода, один универсальный класс использует другой класс с параметрами универсального типа и должен передать один из универсальных типов в метод с параметрами varargs:

class Assembler<X, Y> {
    void assemble(X container, Y... args) { ... }
}

class Component<T> {
    void useAssembler(T something) {

        Assembler<String, T> assembler = new Assembler<String, T>();

        //generates warning:
        // Type safety : A generic array of T is
        // created for a varargs parameter
        assembler.assemble("hello", something);
    }

}

Есть ли какой-нибудь правильный способ передачи универсального параметра в метод varargs без появления этого предупреждения?

Конечно, что-то вроде

assembler.assemble("hello", new T[] { something });

не работает, поскольку вы не можете создавать универсальные массивы.

Ответы [ 8 ]

84 голосов
/ 18 сентября 2009

Кроме добавления @SuppressWarnings("unchecked"), я так не думаю.

Этот отчет об ошибке содержит больше информации, но сводится к тому, что компилятору не нравятся массивы универсальных типов.

57 голосов
/ 29 сентября 2010

Том Хотин указал на это в комментарии, но чтобы быть более точным: да, вы можете решить это на сайте объявлений (а не на (потенциально многих) сайтах вызовов): переключитесь на JDK7.

Как вы можете видеть в блоге Джозефа Дарси , в упражнении Project Coin для выбора некоторых небольших дополнительных улучшений языка для Java 7 принято предложение Боба Ли , разрешающее что-то вроде @SuppressWarnings("varargs") на стороне метода, чтобы это предупреждение исчезло в ситуациях, когда было известно, что оно безопасно.

Это было реализовано в OpenJDK с this commit .

Это может или не может быть полезно для вашего проекта (многие люди не будут рады перейти на нестабильную версию JVM, выпущенную до выпуска!), Но, возможно, это так - или, возможно, тот, кто найдет этот вопрос позже (после JDK7 отсутствует) найдет его полезным.

16 голосов
/ 11 мая 2012

Если вам нужен свободный интерфейс, вы можете попробовать шаблон компоновщика. Не так лаконичен, как varargs, но безопасен для типов.

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

Строитель

public class ArgBuilder<T> implements Iterable<T> {

    private final List<T> args = new ArrayList<T>();

    public ArgBuilder<T> and(T arg) {
        args.add(arg);
        return this;
    }

    @Override
    public Iterator<T> iterator() {
        return args.iterator();
    }

    public static <T> ArgBuilder<T> with(T firstArgument) {
        return new ArgBuilder<T>().and(firstArgument);
    }
}

Используя это

import static com.example.ArgBuilder.*;

public class VarargsTest {

    public static void main(String[] args) {
        doSomething(new ArgBuilder<String>().and("foo").and("bar").and("baz"));
        // or
        doSomething(with("foo").and("bar").and("baz"));
    }

    static void doSomething(Iterable<String> args) {
        for (String arg : args) {
            System.out.println(arg);
        }
    }
}
5 голосов
/ 20 ноября 2011

Явное приведение параметров к Object в вызове метода vararg сделает компилятор счастливым, не прибегая к @ SuppressWarnings.

public static <T> List<T> list( final T... items )
{
    return Arrays.asList( items );
}

// This will produce a warning.
list( "1", 2, new BigDecimal( "3.5" ) )

// This will not produce a warning.
list( (Object) "1", (Object) 2, (Object) new BigDecimal( "3.5" ) )

// This will not produce a warning either. Casting just the first parameter to 
// Object appears to be sufficient.
list( (Object) "1", 2, new BigDecimal( "3.5" ) )

Я считаю, что проблема заключается в том, что компилятор должен выяснить, какой конкретный тип массива создавать. Если метод не является универсальным, компилятор может использовать информацию о типе из метода. Если метод является универсальным, он пытается выяснить тип массива на основе параметров, используемых при вызове. Если типы параметров являются однородными, эта задача проста. Если они различаются, компилятор пытается быть слишком умным, на мой взгляд, и создает универсальный массив типа union. Тогда он вынужден предупредить вас об этом. Более простым решением было бы создать Object [], когда тип не может быть лучше сужен. Приведенное выше решение заставляет именно это.

Чтобы лучше это понять, поэкспериментируйте с вызовами приведенного выше метода списка по сравнению со следующим методом list2.

public static List<Object> list2( final Object... items )
{
    return Arrays.asList( items );
}
2 голосов
/ 24 июня 2016

Вы можете добавить @ SafeVarargs к методу начиная с Java 7, и вам не нужно комментировать клиентский код.

class Assembler<X, Y> {

    @SafeVarargs
    final void assemble(X container, Y... args) {
        //has to be final...
    }
}
1 голос
/ 29 сентября 2010

Вы можете перегружать методы. Это не решит вашу проблему, но минимизирует количество предупреждений (и да, это взлом!)

class Assembler<X, Y> {
  void assemble(X container, Y a1) { ... }
  void assemble(X container, Y a1, Y a2) { ... }
  void assemble(X container, Y a1, Y a2, Y a3) { ... }
  void assemble(X container, Y a1, Y a2, Y a3, Y a4) { ... }
  void assemble(X container, Y... args) { ... }
}
1 голос
/ 18 сентября 2009

Очень легко решить проблему: используйте List<T>!

Массивы ссылочного типа следует избегать.

В текущей версии Java (1.7) вы можете пометить метод с помощью @SafeVargs, который удалит предупреждение из вызывающей стороны. Осторожнее с этим, и вам все еще лучше без устаревших массивов.

См. Также Улучшенные предупреждения и ошибки компилятора при использовании формальных параметров без переопределения с методами Varargs Техническое примечание.

0 голосов
/ 18 сентября 2009

При работе с массивами универсального типа я вынужден передавать ссылку на универсальный тип. С этим я действительно могу сделать общий код, используя java.lang.reflect.Array.

http://java.sun.com/javase/6/docs/api/java/lang/reflect/Array.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...