2015-05-28 5 views
12

Как ссылаются на < < T >> обрабатывается компилятором в следующем коде, так как метод не принимает параметров, которые позволили бы вывести T? Существуют ли какие-либо ограничения на то, какой тип объекта может быть помещен в список? Является ли приведение даже в строке, где я добавляю строку в список? Моя первая мысль состоит в том, что без каких-либо выводов T от T становится типом объекта. Заранее спасибо.Как параметризованные методы разрешают <T>, если это не входной параметр?

public class App { 

private <T> void parameterizedMethod() 
{ 
    List<T> list = new ArrayList<>(); 
    for(int i = 0; i < 10; i++) 
    { 
     list.add((T)new String()); //is a cast actually occurring here? 
    } 
} 

public App() 
{ 
    parameterizedMethod(); 
} 

public static void main(String[] args) { 
    new App(); 
} 
} 

ответ

0
List<T> list = new ArrayList<>(); 
for(int i = 0; i < 10; i++) 
{ 
    list.add((T)new String()); //is a cast actually occurring here? 
} 

Нет, не литой фактически не происходит там. Если вы сделали что-то с list, что вынудило его быть List<T> - например, вернуть его - тогда это может привести к тому, что ClassCastException s в точке, где компилятор вставил реальный литой.

4

Это изначально определяется 18.1.3:

Когда начинается вывод, связанное множество, как правило, генерируется из списка деклараций параметров типа P1, ..., Pp и связанных с ними вывода переменных α1, ..., αp. Такое связанное множество строится следующим образом. Для каждого л (1 ≤ L ≤ р):

  • Если Pl не имеет TypeBound, связанного αl <: Object появляется в наборе.

  • В противном случае, для каждого типа T, ограниченной & в TypeBound, связанный αl <: T[P1:=α1, ..., Pp:=αp] появляется в наборе; [...].

В конце вывода, связанный набор получает «решен» с выведенным типом. Без какого-либо дополнительного контекста связанный набор будет состоять только из начальных границ, основанных на объявлении параметра типа.

связанный с формой, как αl <: Object означает αl (переменный логический вывод) является Object или подтип Object. Эта граница разрешена к Object.

Так что в вашем случае, да, Object выведено.

Если мы объявили тип связанного:

private <T extends SomeType> void parameterizedMethod() 

тогда SomeType будет выведенный.


В данном случае никакого наложения не происходит (стирание). Вот почему это «непроверено». Литая происходит только тогда, когда объект подвергается воздействию вследствие например .:

<T> T parameterizedMethodWithAResult() 
{ 
    return (T) new String(); 
} 

// the cast happens out here 
Integer i = parameterizedMethodWithAResult(); 
// parameterizedMethodWithAResult returns Object actually, 
// and we are implicitly doing this: 
Integer i = (Integer) parameterizedMethodWithAResult(); 

ли какие-либо ограничения, которые размещены на какой тип объекта может быть помещен в список?

Семантически (время компиляции), да. И обратите внимание, что ограничение определяется за пределами метод. Внутри метод, мы не знаем, какое это ограничение на самом деле. Поэтому мы не должны ставить String в List<T>. Мы не знаем, что такое T.

Практически (время работы), нет. Это всего лишь List, и нет проверочного списка. parameterizedMethod не вызывает исключения ... но это справедливо только для такого рода изолированного примера. Такой код может привести к проблемам.

+0

спасибо. То, что я с тех пор нашел, также очень интересно, так это то, что компилятор заставляет меня сохранять приведение в (T) при добавлении новой строки в список. Поэтому, хотя мы не знаем, что такое T (хотя, как вы указываете, это объект), я вынужден использовать все, что я добавляю в список, к (T). – swingMan

+0

Правильно, у нас есть некоторое представление о том, что такое 'T'", но мы точно не знаем. Компилятор использует это неизвестное. – Radiodef

1

Внутри тела метода Java не предоставляет нам никакой информации о замене для T, так как мы можем сделать что-нибудь полезное с T?

Иногда, T не имеет отношения к телу метода; это просто удобнее для звонящего

public static List<T> emptyList(){...} 

    List<String> emptyStringList = emptyList(); 

Но если T важно тело метода, должны быть вне зоны протокола, не подлежит исполнению компилятором, что и вызывающий и вызываемый абонент должен подчиняться. Например

class Conf 
    <T> T get(String key) 

// 
<conf> 
    <param name="size" type="int" ... 

// 
String name = conf.get("name"); 
Integer size = conf.get("size"); 

API-интерфейс использует <T> здесь просто так, что вызывающий абонент не должен делать явное приведение. Обязанностью вызывающего абонента является обеспечение правильного ввода T.

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

<T super String> void parameterizedMethod() 
{ 
    List<T> list 
    ... 
    list.add(new String()); // obviously correct; no cast is needed 
} 

// 
this.<Integer>parameterizedMethod(); // compile error 

, к сожалению,, Java не поддерживает <T super Foo> ... :) Так что вам нужно Javadoc ограничение вместо

/** T must be a supertype of String! **/ 
<T> void parameterizedMethod() 

У меня есть фактический API example именно так.

 Смежные вопросы

  • Нет связанных вопросов^_^