2014-01-27 3 views
4

Насколько я знаю, использование верхнего ограниченного общего и использование суперкласса в качестве параметра метода принимают одинаковые возможные аргументы. Что предпочтительнее, и какая разница между ними, если таковая имеется?Верхние ограниченные генерические элементы VS-суперкласс как параметры метода?

ограничена сверху родовое в качестве параметра:

public <T extends Foo> void doSomething(T foo) {} 

суперкласса в качестве параметра:

public void doSomething(Foo foo) {} 

ответ

3

Это верхний параметр ограниченного типа. Нижние границы создаются с использованием super, что вы действительно не можете сделать для параметра типа. You can't have a lower bounded type parameter.

И это будет иметь значение, если вы, например, хотите передать List<T>. Таким образом, для указанных ниже двух методов:

public <T extends Foo> void doSomething(List<T> foos) {} 
public void doSomething(List<Foo> foo) {} 

И для данного класса:

class Bar extends Foo { } 

Следующий вызов метода:

List<Bar> list = new ArrayList<Bar>(); 
doSomething(list); 

действителен для 1-го метода, но не для 2-го метод. Второй метод терпит неудачу, потому что List<Foo> не является супер-типом List<Bar>, хотя Foo является супер-типом Bar. Тем не менее, первый метод проходит, поскольку там параметр типа T будет выведен как Bar.

+0

Я вижу. Есть ли причина использовать суперкласс в качестве параметра? Или это просто соглашение использовать его, когда вы можете? – Someone

+0

@Someone Когда вы просто передаете один аргумент типа 'Foo' или его подтип, вам не нужен общий метод. Вы можете передать экземпляр подкласса 'Foo' в тип параметра' Foo'. –

+1

Это отвечает на другой вопрос. В исходном вопросе 'Foo' является супертипом' T'. Если в вашем случае 'List ' не является супертипом 'List ', значит, так оно и есть. В вашем случае супертип для 'List ' вместо этого будет 'List '. – newacct

1

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

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

public static <T> void addToList(List<T> list, T element) { 
    list.add(element); 
} 

Это тривиальный пример, но вы можете видеть, что это мешает вам придав ему элемент, который не делает соответствует общий тип списка в:

List<Integer> list = new ArrayList<>(); 
addToList(list, 7); 
//addToList(list, 0.7); // doesn't compile 
//addToList(list, "a"); // doesn't compile 

Вы также можете объявить параметр и тип возвращаемого быть тот же тип:

public static <T> T nullCheck(T value, T defValue) { 
    return value != null ? value : defValue; 
} 

Поскольку этот метод возвращает один из двух заданных объектов T, мы можем с уверенностью сказать, что возвращаемый объект также имеет тип T.

Integer iN = null; 
Integer i = nullCheck(iN, 7); 
System.out.println(i); // "7" 

Double dN = null; 
Double d = nullCheck(dN, 0.7); 
System.out.println(d); // "0.7" 

Number n = nullCheck(i, d); // T = superclass of Integer and Double 
System.out.println(n); // "7" 

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

Также следует отметить, что другой ответ изменяет пример использования List<T> и List<Foo>, но, как упоминалось в комментариях, суперкласс действительно List<? extends Foo>, поэтому нет тип переменной нужен там, либо.

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