tags:

views:

508

answers:

3

Is there a difference between Enumeration<? extends ZipEntry> and Enumeration<ZipEntry>? If so, what is the difference?

+11  A: 

There's no practical difference in terms of what you can do when you've got one of them, because the type parameter is only used in an "output" position. On the other hand, there's a big difference in terms of what you can use as one of them.

Suppose you had an Enumeration<JarEntry> - you couldn't pass this to a method which took Enumeration<ZipEntry> as one of its arguments. You could pass it to a method taking Enumeration<? extends ZipEntry> though.

It's more interesting when you've got a type which uses the type parameter in both input and output positions - List<T> being the most obvious example. Here are three examples of methods with variations on a parameter. In each case we'll try to get an item from the list, and add another one.

// 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);
}

For more details, read:

Jon Skeet
A ZipEntrySubclass like JarEntry (the reason why ZipFile.entries uses a wildcard)?
Tom Hawtin - tackline
Thanks Tom - will edit my answer :)
Jon Skeet
+4  A: 

Yes, straight from one of the sun generics tutorials:

Here Shape is an abstract class with three subclasses: Circle, Rectangle, and Triangle.

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

It is worth noting that the draw() method can only be called on lists of Shape and cannot be called on a list of Circle, Rectangle, and Triangle for example. In order to have the method accept any kind of shape, it should be written as follows:

public void draw(List<? extends Shape> shape) {
   // rest of the code is the same
}
GaryF
This is the second time this week Jon Skeet has gotten an answer in just before me. I propose we refer to this as Skeeting.
GaryF
sounds good. what would the past tense be? Sket? "Jon Skeet sket me AGAIN!" :)
Epaga
http://stackoverflow.com/questions/305223/jon-skeet-facts/317486#317486
Michael Myers
A: 

Now you've just gone and reminded me of something I wish we had over in the C# world.

Other than the links provided, there's some good links about C# and Java in relation to this topic in the answers to this question: http://stackoverflow.com/questions/110121

A selection of which are:

Matthew Scharley