Какова цель аргументов типа в вызове constructor после new?

В спецификации Java (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.9) новый имеет следующую форму:

ClassInstanceCreationExpression ::=
| new TypeArguments_opt TypeDeclSpecifier TypeArgumentsOrDiamond_opt
    ( ArgumentListopt ) ClassBodyopt
| Primary . new TypeArguments_opt Identifier TypeArgumentsOrDiamond_opt
    ( ArgumentListopt ) ClassBodyopt

Какова цель первого необязательного списка аргументов типа после нового? Мне не удалось найти его из моего чтения раздела 15.9 (все ссылки на список аргументов типа, похоже, относятся к списку после типа/идентификатора). Тестирование случайных бит на стандартном компиляторе Java приводит к запутывающим результатам:

public class Foo<T> { }
// ...
Foo<Integer> t1 = new <Integer> Foo<Integer>();  // works
Foo<Integer> t2 = new <Integer> Foo();           // works -- unchecked warning missing the type arg after Foo
Foo<Integer> t3 = new <Boolean> Foo<Integer>();  // works
Foo<Integer> t4 = new <Float, Boolean> Foo<Integer>();  // works
Foo<Integer> t5 = new <NotDefined> Foo<Integer>();  // fails -- NotDefined is undefined

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

Ответ 1

Конструкторы могут также объявлять параметры типа

public class Main {     
    public static class Foo<T> {
        public <E> Foo(T object, E object2) {

        }
    }
    public static void main(String[] args) throws Exception {
        Foo<Integer> foo = new <String> Foo<Integer>(1, "hello");           
    }    
}

То, что означает <String>, предшествующее вызову конструктора. Это аргумент типа для конструктора.

Следующие

Foo<Integer> foo = new <String> Foo<Integer>(1, new Object());

не работает с

Параметрированный конструктор Foo (Integer, String) типа Main.Foo не применим для аргументов (Integer, Объект)

В вашем последнем

Foo<Integer> t5 = new <NotDefined> Foo<Integer>();  // fails -- NotDefined is undefined

NotDefined - это не тип, который находится во время компиляции. Если бы это было так, вы просто предупредили, что это unused.

Ответ 2

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

Math.<Runnable>max(1,2);

System.out.<Button>println();

см. http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.1-200-E

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

Это правило связано с проблемами совместимости и принципами взаимозаменяемости. Поскольку интерфейсы или суперклассы могут генерироваться независимо от их подтипов, мы можем переопределить общий метод с не общим. Однако переопределяющий (не общий) метод должен быть применим к вызовам общего метода, включая вызовы, явно передающие аргументы типа. В противном случае подтип не подменялся бы для его обобщенного супертипа.