Java 7 Diamond Операция в вызове метода
Это своего рода дополнительный вопрос к обсуждению:
Почему оператор Diamond не работает в вызове addAll() в Java 7?
Из учебника по Java,
http://docs.oracle.com/javase/tutorial/java/generics/gentypeinference.html
Обратите внимание, что ромб часто работает в вызовах методов; однако для большей ясности предлагается использовать ромб в первую очередь для инициализации переменной, в которой он объявлен
Итак, я немного запутался в первой строке. Когда работает алмаз в вызовах методов?
Немного больше объяснения о том, как работает алмазный оператор, можно найти здесь:
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html?
И из этого я попробовал следующее, которое отлично работает:
Дай что у меня есть:
private static class Box<T>{
public Box(T t){}
}
static void f(Box<Integer> box){}
вызов вроде следующего компилируется нормально:
f(new Box<>(new Integer(10)));
Параметр типа при вызове конструктора в вызове метода f()
выше выводится из аргумента в конструктор (т.е. Integer
).
Так это то, что подразумевается, когда учебник говорит
Обратите внимание, что алмаз часто работает в вызовах методов
Если нет, может ли кто-нибудь любезно привести пример, в котором алмаз работает в вызове метода?
3 ответа
Так это то, что подразумевается, когда учебник говорит
Я думаю, что да, хотя есть несколько ошибок, когда дело доходит до <>
операторы.
В вашем случае инстанцирование Box не является проблемой, учитывая, что тип может быть тривиально выведен с помощью аргумента конструктора. Попробуйте изменить конструктор, чтобы "не" взять в Integer
или же T
и посмотрите, как не удается вызвать.
class BadBox<T> {
private T t;
public BadBox(){}
public void setT(T t) {
this.t = t;
}
static void f(BadBox<Integer> box){}
public static void main(final String[] args) {
f(new BadBox<>()); //fails, should have worked ideally
}
}
Точно так же посмотрите на этот класс:
class Testi<R> {
public void doIt(Set<? extends R> sets) {
}
public static void main(final String[] args) {
// works since type inference is now possible
new Testi<CharSequence>().doIt(new HashSet<>(Arrays.asList("a")));
// fails; nothing which can help with type inference
new Testi<CharSequence>().doIt(new HashSet<>();
}
}
Точно так же проблема в вашем связанном вопросе (относительно addAll
) может быть просто решена, помогая компилятору немного следующим образом:
List<String> list = new ArrayList<>();
list.add("A");
// works now! use only if you love diamond operator ;)
list.addAll(new ArrayList<>(Arrays.asList(new String[0])));
// or the old-school way
list.addAll(new ArrayList<String>()));
Алмазные операторы также, кажется, ломаются, когда дело доходит до реализации анонимных классов следующим образом:
final String[] strings = { "a", "b", "c" };
Arrays.sort(strings, new Comparator<>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
});
К счастью, в этом случае компилятор довольно явно упоминает, что <>
не работает / не работает с анонимными классами.
Я не думаю, что стоит думать о том, когда это работает, а когда нет. Компилятор скажет вам, и поэтому вы должны переписать то, что не работает.
За этим нет реального обоснования; это скорее похоже на то, что разработчики поместили текущие ограничения реализации фактического компилятора в конкретное время в спецификации и сказали нам: так оно и должно быть.
Java 8 снимает многие из этих ограничений без адской заморозки. Например
Arrays.asList("foo", "bar").addAll(new ArrayList<>());
компилируется с Java 8 без ошибок. И почему бы нет?
Дело не в вызове метода. Автономное заявление
new Box<>(new Integer(10));
также компилирует. Есть достаточно информации, чтобы сделать вывод T
за Box
(т.е. из аргумента Integer)
С другой стороны, это не компилируется
new ArrayList<>();
Нет никакого способа узнать, какой список желателен.
Collection<String> strings = new ArrayList<>();
это работает, потому что вывод помогает тип цели Collection<String>