2013-09-08 3 views
10

В спецификации 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 

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

ответ

13

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

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, Object)

В последних

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

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

+0

Отлично. В этом есть смысл. Что еще запутывает, так это то, что вы можете указать параметры типа для вызова конструктора, который не указывает аргументы типа. Какие там правила? – psosera

+0

Компилятор Eclipse просто предупреждает «Неиспользуемые аргументы типа для не общего конструктора». Аналогично методам с параметрами типа вам не нужно указывать '<...>', если он может быть выведен из типа аргумента. –

+0

Ах. Интересно. 'javac' не дает никаких предупреждений (даже с -Xlint: предупреждениями), которые, вероятно, являются корнем моей путаницы. Мне странно, что вы можете «переопределить» параметры типа, подобные этому (т. Е. Параметры типа поставки, которые конструктор не использует). Независимо от того, что это такое, я думаю. Благодаря! (Я предполагаю, что причина, по которой Java допускает это, связана с стиранием родового типа. Если кто-то еще может заполнить детали, это было бы здорово!) – psosera

3

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

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

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

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

+0

Подозреваемый. Спасибо за дополнительную информацию! – psosera