Spec-Zone .ru
спецификации, руководства, описания, API
|
Вывод типа является возможностью компилятора Java смотреть на каждый вызов метода и соответствующее объявление, чтобы определить параметр типа (или параметры), которые делают вызов применимым. Алгоритм вывода определяет типы параметров и, при наличии, тип, что результат присваивается, или возвращается. Наконец, алгоритм вывода пытается найти наиболее определенный тип, который работает со всеми параметрами.
Чтобы проиллюстрировать этот последний тезис, в следующем примере, вывод решает, что второй параметр, который передают к методу pick, имеет тип String:
static <T> T pick(T a1, T a2) { return a2; } Serializable s = pick("d", new ArrayList<String>());
Универсальные Методы, представленные Вы выводу типа, который позволяет Вам вызвать универсальный метод, поскольку Вы были бы обычный метод, не определяя тип между угловыми скобками. Рассмотрите следующий пример, BoxDemo
, который требует Box
class:
public class BoxDemo { public static <U> void addBox(U u, java.util.List<Box<U>> boxes) { Box<U> box = new Box<>(); box.set(u); boxes.set(box); } public static <U> void outputBoxes(java.util.List<Box<U>> boxes) { int counter = 0; for (Box<U> box: boxes) { U boxContents = box.get(); System.out.println("Box #" + counter + " contains [" + boxContents.toString() + "]"); counter++; } } public static void main(String[] args) { java.util.ArrayList<Box<Integer>> listOfIntegerBoxes = new java.util.ArrayList<>(); BoxDemo.<Integer>addBox(Integer.valueOf(10), listOfIntegerBoxes); BoxDemo.addBox(Integer.valueOf(20), listOfIntegerBoxes); BoxDemo.addBox(Integer.valueOf(30), listOfIntegerBoxes); BoxDemo.outputBoxes(listOfIntegerBoxes); } }
Следующее является выводом от этого примера:
Box #0 contains [10] Box #1 contains [20] Box #2 contains [30]
Универсальный метод addBox
определяет один названный параметр типа U
. Обычно, компилятор Java может вывести параметры типа универсального вызова метода. Следовательно, в большинстве случаев, Вы не должны определить их. Например, чтобы вызвать универсальный метод addBox
, можно определить параметр типа следующим образом:
BoxDemo.<Integer>addBox(Integer.valueOf(10), listOfIntegerBoxes);
Альтернативно, если Вы опускаете параметры типа, компилятор Java автоматически выводит (от параметров метода), который параметр типа Integer
:
BoxDemo.addBox(Integer.valueOf(20), listOfIntegerBoxes);
Можно заменить параметры типа, требуемые вызвать конструктора универсального class с пустым множеством параметров типа (<>
) пока компилятор может вывести параметры типа от контекста. Эту пару угловых скобок неофициально вызывают ромбом.
Например, рассмотрите следующее объявление переменной:
Map<String, List<String>> myMap = new HashMap<String, List<String>>();
Вы можете subsitute parameteried тип конструктора с пустым множеством параметров типа (<>):
Map<String, List<String>> my Map = newHashMap<>();
Отметьте, что, чтобы использовать в своих интересах вывод типа во время универсального инстанцирования class, Вы должны ромбовидная нотация. В следующем примере компилятор генерирует преобразование непроверенное, предупреждающее потому что HashMap()
конструктор обращается к HashMap
необработанный тип, не Map<String, List<String>>
введите:
Map<String, List<String>> myMap = new HashMap(); // unchecked conversion warning
Java поддерживает ограниченный вывод типа для универсального создания экземпляра; можно только использовать вывод типа, если параметризованный тип конструктора очевиден из контекста. Например, следующий код не компилирует:
List<String> list = new ArrayList<>(); list.add("A"); // The following statement should fail since addAll expects // Collection<? extends String> list.addAll(new ArrayList<>());
Отметьте, что ромб часто работает в вызовах метода; однако, для большей ясности, предлагается, чтобы Вы использовали ромб прежде всего, чтобы инициализировать переменную, где это объявляется.
В сравнении, следующих компиляциях в качестве примера:
List<? extends String> list2 = new ArrayList<>(); list.addAll(list2);
Отметьте, что конструкторы могут быть универсальными (другими словами, объявите их собственные формальные параметры типа), и в универсальных и в неуниверсальных классах. Рассмотрите следующий пример:
class MyClass<X> { <T> MyClass(T t) { // ... } }
Рассмотрите следующее инстанцирование class MyClass
:
new MyClass<Integer>("")
Этот оператор создает экземпляр параметризованного типа MyClass<Integer>
; оператор явно определяет тип Integer
для формального параметра типа, X
, из универсального class MyClass<X>
. Отметьте, что конструктор для этого универсального class содержит формальный параметр типа, T
. Компилятор выводит тип String
для формального параметра типа, T
, из конструктора этого универсального class (потому что фактический параметр этого конструктора является a String
объект).
Компиляторы от выпусков до Java SE 7 в состоянии вывести фактические параметры типа универсальных конструкторов, подобных универсальным методам. Однако, компиляторы в Java, SE 7 и позже может вывести фактические параметры типа универсального class, который инстанцируют, если Вы используете ромб (<>
). Рассмотрите следующий пример:
MyClass<Integer> myObject = new MyClass<>("");
В этом примере компилятор выводит тип Integer
для формального параметра типа, X
, из универсального class MyClass<X>
. Это выводит тип String
для формального параметра типа, T
, из конструктора этого универсального class.