Подтвердить что ты не робот

Необычный общий синтаксис: Массивы. <String> asList (...)

Я нашел "необычный" общий синтаксис, например:

Arrays.<String>asList(...);
Collections.<String>emptyList();

Очевидно, что результаты методов являются общими. Является ли такой синтаксис для проверки типов? Массив Object не может быть аргументом для Arrays.<String>asList(...).

4b9b3361

Ответ 1

<typearg>methodname - это синтаксис для явного указания аргумента типа для универсального метода

Когда вы используете универсальный класс, вы обычно должны указывать аргумент типа (например, String):

ArrayList<String> list =  new ArrayList<String>();

При использовании универсального метода вы обычно не передаете аргумент типа:

public static <T> void foo(T param) {   }
...
String s = ...;
MyClass.foo(s);

Вы не заметите, где мы сделали код, явно указав, что мы хотим String версию foo, т.е. не было задано явного аргумента типа <String>, как мы видели при использовании универсального класса (List<String>).

Компилятор делает некоторую магию компилятора, чтобы вывести аргумент универсального типа на основе контекста. Это отличная вещь и очень мощная.

Однако иногда компилятор не может автоматически определить аргументы типа:

public static <T> void bar() { T myLocalVar = ...; ...  }
MyClass.bar();

Какую конкретную версию bar мы пытаемся вызвать, т.е. каков аргумент типа для этого вызова? Не знаю? Ну, компилятор тоже нет. Мы должны явно указать аргумент типа, как мы обычно делаем при использовании универсального класса:

MyClass.<String>bar();

Также см.:


Помимо этого: возможно, стоит упомянуть, что в Java 7 будет добавлен так называемый оператор diamond, чтобы позволить компилятору выводить аргументы типа при использовании обобщенных классов:

ArrayList<String> list =  new ArrayList<String>();

становится

ArrayList<String> list =  new ArrayList<>();

В чем смысл бриллиантового оператора (& lt; & gt;) в Java 7?

Ответ 2

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

Ответ 3

Ответы, приведенные выше, в значительной степени затрагивают ваш вопрос, но если вы хотите указать конкретный пример случая, когда вывод типичного типа Java завершился неудачно, и явно заявив, что он таким образом сохраняет день, рассмотрите следующие определения классов:

public class A { }
public class B extends A { }
public class C extends A { }

Тогда следующий код работает просто отлично (например, вывод типа Java преуспевает):

List<Class<? extends A>> list = ImmutableList.of(B.class, C.class);

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

List<Class<? extends A>> list = ImmutableList.of(B.class);

Это право; как ни странно, удалив параметр, мы путаем систему вывода типа, так как "ближайший общий потомок" B.class и C.class равен A.class, но для B.class сам он просто B.class, что (из-за отсутствия ковариации в Java-генериках) не соответствует List<Class<? extends A>>. В этом случае у вас нет выбора, кроме как использовать:

List<Class<? extends A>> list = ImmutableList.<Class<? extends A>>of(B.class);

Так как B действительно расширяет A, это компилирует (и работает) просто отлично.

Я надеюсь, что эта демонстрация подчеркивает полезность оператора.

Ответ 4

Кроме того, после Java 7 компилятор поддерживает вывод типа. Рассмотрим следующие определения классов:

public class A { }
public class B extends A { }
public class C extends A { }

Все следующие случаи работают:

List<Class<? extends A>> list0 = Arrays.asList(B.class, C.class);
List<Class<? extends A>> list1 = Arrays.asList(B.class);

List<A> list2 = Arrays.asList(new B());
List<A> list3 = Arrays.asList(new B(), new C());


List<? extends A> list4 = Arrays.asList(new B(), new C());
List<? extends A> list5 = Arrays.asList(new B());