Разница между перечислением‹? расширяет ZipEntry› и Enumeration‹ZipEntry›?

Есть ли разница между перечислением‹? расширяет ZipEntry› и Enumeration‹ZipEntry›? Если да, то в чем разница?


person Epaga    schedule 06.03.2009    source источник


Ответы (3)


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

Предположим, у вас есть Enumeration<JarEntry> — вы не можете передать его методу, который принимает Enumeration<ZipEntry> в качестве одного из своих аргументов. Однако вы можете передать его методу, принимающему Enumeration<? extends ZipEntry>.

Более интересно, когда у вас есть тип, который использует параметр типа как во входных, так и в выходных позициях — List<T> является наиболее очевидным примером. Вот три примера методов с вариациями параметра. В каждом случае мы попытаемся получить элемент из списка и добавить еще один.

// Very strict - only a genuine List<T> will do
public void Foo(List<T> list)
{
    T element = list.get(0); // Valid
    list.add(element); // Valid
}

// Lax in one way: allows any List that's a List of a type
// derived from T.
public void Foo(List<? extends T> list)
{
    T element = list.get(0); // Valid
     // Invalid - this could be a list of a different type.
     // We don't want to add an Object to a List<String>
    list.add(element);   
}

// Lax in the other way: allows any List that's a List of a type
// upwards in T's inheritance hierarchy
public void Foo(List<? super T> list)
{
    // Invalid - we could be asking a List<Object> for a String.
    T element = list.get(0);
    // Valid (assuming we get the element from somewhere)
    // the list must accept a new element of type T
    list.add(element);
}

Для получения более подробной информации прочитайте:

person Jon Skeet    schedule 06.03.2009
comment
Подкласс ZipEntrySubclass, такой как JarEntry (причина, по которой ZipFile.entries использует подстановочный знак)? - person Tom Hawtin - tackline; 06.03.2009

Да, прямо из одного из руководств по универсальным средствам Sun:

Здесь Shape — это абстрактный класс с тремя подклассами: Circle, Rectangle и Triangle.

public void draw(List<Shape> shape) {
  for(Shape s: shape) {
    s.draw(this);
  }
}

Стоит отметить, что метод draw() можно вызывать только для списков Shape и нельзя вызывать, например, для списков Circle, Rectangle и Triangle. Чтобы метод принимал любую форму, он должен быть записан следующим образом:

public void draw(List<? extends Shape> shape) {
   // rest of the code is the same
}
person GaryF    schedule 06.03.2009
comment
Второй раз на этой неделе Джон Скит получил ответ как раз передо мной. Я предлагаю называть это скитингом. - person GaryF; 06.03.2009
comment
звучит неплохо. каким будет прошедшее время? Скет? Джон Скит СНОВА рисует меня! :) - person Epaga; 06.03.2009

Вы только что ушли и напомнили мне о чем-то, что мне хотелось бы иметь в мире C#.

Помимо предоставленных ссылок, в ответах на этот вопрос есть несколько хороших ссылок о C# и Java, связанных с этой темой: Logic and its application to Collections .Generic и наследование

Выбор из которых:

person Matthew Scharley    schedule 06.03.2009