Java 7 Diamond Операция в вызове метода - PullRequest
9 голосов
/ 26 декабря 2011

Это своего рода дополнительный вопрос в обсуждении:

Почему оператор Diamond не работает в вызове addAll () в Java 7?

Из учебника Java

http://docs.oracle.com/javase/tutorial/java/generics/gentypeinference.html

Обратите внимание, что ромб часто работает в вызовах методов;однако, для большей ясности, предлагается использовать алмаз в основном для инициализации переменной, в которой он объявлен

Итак, я немного запутался в первой строке.Когда работает diamond в вызовах методов?

Здесь можно найти немного больше объяснений о том, как работает оператор diamond:

http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#What%20is%20type%20argument%20inference%20for%20constructors?

ИИсходя из этого, я попробовал следующее, что прекрасно работает:

Дайте, что у меня есть:

private static class Box<T>{
    public Box(T t){}
}
static void f(Box<Integer> box){}

вызов, как следующий, прекрасно компилируется:

f(new Box<>(new Integer(10)));

Параметр типа при вызове конструктора в вызове метода f() выше выводится из аргумента конструктора (то есть Integer).

Так вот, что имеется в виду, когда в учебнике написано

Обратите внимание, что ромб часто работает в вызовах методов

Если нет, может кто-нибудь достаточно любезенпривести пример, где diamond работает в вызове метода?

Ответы [ 3 ]

3 голосов
/ 26 декабря 2011

Так вот что подразумевается, когда в учебнике написано

Я думаю, что да, хотя есть пара ошибок, когда дело доходит до <> операторов.

В вашем случае инстанцирование Box не является проблемой, учитывая, что тип может быть легко выведен с помощью аргумента конструктора. Попробуйте изменить конструктор на «not», взяв 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;
    }
});

К счастью, в этом случае компилятор довольно явно упоминает, что <> не работает / не будет работать с анонимными классами.

1 голос
/ 05 февраля 2014

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

За этим нет реального обоснования; это скорее похоже на то, что разработчики поместили текущие ограничения фактической реализации компилятора в конкретное время в спецификацию и сказали нам: так оно и должно быть.

Java 8 снимает многие из этих ограничений без адского замерзания. Э.Г.

Arrays.asList("foo", "bar").addAll(new ArrayList<>());

компилируется с Java 8 без ошибок. И почему бы и нет?

0 голосов
/ 27 декабря 2011

Дело не в вызове метода. Автономное заявление

new Box<>(new Integer(10));

также компилируется. Достаточно информации для вывода T для Box (т.е. из аргумента Integer)

С другой стороны, это не компилируется

new ArrayList<>();

Нет способа узнать, какой список нужен.

Collection<String> strings = new ArrayList<>();

это работает, потому что вывод помогает тип цели Collection<String>

...