Почему в этом общем методе есть лишние <E>? - PullRequest
12 голосов
/ 14 ноября 2011

Некоторое время назад я изучил дженерики java, но сейчас я изучаю коллекции и нашел некоторый код, который мне не понятен. Вот код:

static <E> List<E> nCopies(int n, E value)

Это из класса java.util.Collections.

Мой вопрос, почему есть:

<E> List<E>

и не только

List<E>

Очевидно, что я что-то упускаю, кто-то может уточнить это для меня?

Ответы [ 4 ]

14 голосов
/ 14 ноября 2011

Вы используете <E>, чтобы типизировать метод, который вы определяете.

Наиболее распространенный пример обобщенных типов - это иметь типизированный класс, подобный этому:

public class SomeClass<E> {
    ...
}

Тогда, когдавы создаете новый объект этого класса, определяя тип непосредственно следующим образом:

new SomeClass<String>();

Таким образом, любой метод в этом классе, который ссылается, будет обрабатываться как строка для этого экземпляра.

Теперь рассмотрим статический метод (который не привязан к какому-либо конкретному экземпляру класса), чтобы типизировать этот метод, вы используете другой тип типизации, который применяется к методам, например:

static <E> List<E> nCopies(int n, E value)

Вы используете <E> перед возвращаемым типом, чтобы сказать «этот конкретный метод будет учитывать некоторое E при выполнении».Что будет <E> будет решено, когда вы вызовете метод:

nCopies(3, "a");

В этом примере <E> будет String, поэтому тип возвращаемого значения будет List<String>.

Наконец, вы можете даже смешать их обоих:

public class SomeClass<E> {
    public <F> void doSomething(E e, F f){
        ...
    }
}

В этом случае, если у вас есть экземпляр SomeClass, E в методе doSomething всегда будет String (для этого экземпляра), но Fможет быть чем угодно.

11 голосов
/ 14 ноября 2011

В <E> List<E> первый <E> означает, что E является параметром типа . Если вы не указали это, то Java подумает, что E в E value относится к фактическому классу с именем E, и попросит вас импортировать его. См. универсальные методы .

4 голосов
/ 14 ноября 2011

<E> требуется, чтобы сообщить компилятору, что вы намереваетесь использовать E в качестве параметра типа, так же, как при создании универсального класса (например, public interface List<E>).

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

Редактировать

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

Вот пример того, где вы могли бы иметь это:

public class MyList<E> {

    public <N super E> MyList<N> createCopy() {
        //...
    }
}

Этот метод позволит вам создать копию списка, но не будет ограничивать вас в использовании того же типа, что и ваш список, а позволит вам использовать супертип.Например:

MyList<Integer> integers = createList(1, 2, 5);
MyList<Number> numbers = integers.createCopy();
2 голосов
/ 14 ноября 2011

List<E> - это возвращаемый тип для метода, тогда как <E> - это передаваемый тип (это выводится компилятором из того, что передается как E value).

static <E> List<E> someMethod(E myObject)
{
    E objectOfMyType = myObject;
    List<E> myList = new ArrayList<E>();
    ...
    return myList; 
}

Это будет называться:

MyObject o = new MyObject();
List<MyObject> myList = SomeClass.someMethod(o);

ИМХО синтаксис для методов довольно тупой, но он у вас есть.Соответствующее руководство по Oracle находится здесь: http://download.oracle.com/javase/tutorial/extra/generics/methods.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...