Super Generation

I would like to write Interator as follows:

class Plant { } class Tree extends Plant { } class Maple extends Tree { } // Iterator class: compiler error on the word "super". class MyIterator<T super Maple> implements Iterator<T> { private int index = 0; private List<Maple> list = // Get the list from an external source. public T next() { Maple maple = list.get(index++); // Do some processing. return maple; } // The other methods of Iterator are easy to implement. } 

Conceptually, the idea is to have an iterator that looks like it returns trees or plants (even if they are always maples) without writing separate classes for each.

But the compiler does not like it when I generate using T super Maple ; apparently you can only generate a class using T extends Something . Does anyone know of a good way to accomplish the same thing?

My motivation for the request is that I have a program that uses interfaces for its API. I want to have one method that returns an iterator of interfaces (for API), and another that returns an iterator of implementation classes (for internal use).

+7
source share
5 answers
+4
source

If Maple is a Tree and a Plant , because it extends both of these, what is a point, then in the super clause that you want to use? You can assign Mapple to Object , Tree or Plant links to the classic subtype of polymorphism.

Both ? extends T and ? super T ? super T are wildcards declared as type arguments to replace a parameter of type T

What you intend to do is determine the boundary of the type argument, not the type parameter. You can simply declare your type parameter as T without restrictions, and then when you use it, you use a wildcard as the type argument.

 class MyIterator<T> implements Iterator<T> { ... } 

And when you use it:

 MyIterator<? super Maple> iter; 
+3
source

So, your iterator returns an iterator over the maple, but you want to use it as an iteratorr over Plant.

Suppose (for a moment) that Iterator had an insertInto (T t) method that puts the object in the list at the point where the iterator is located. If you select the iterator as Iterator <Plant> then this would mean that it would be ok to call i .insertInto (myCarrot) - because carrots are plants. But this will violate the types - it will try to put carrots on the main list of maples.

In other words, your iterator is not an iterator over Plants, it will not only accept any old plant as an argument to the method, and why you cannot distinguish it or generate it as such.

+1
source

The declaration of the super -bounded type parameter is not allowed, and the argument is that it is not useful .

You managed to stumble upon a funny case where, well, that makes sense, because if you use a read-only iterator, it might be convenient to link it like this.

A simple option is to just let it be and implement Iterator<Maple> , or Iterator<T> with some type checking.

0
source

There seems to be no perfect way to do this, so I suggest two suboptimal solutions.

The first is a wrapper iterator:

 public class SuperTypeIterator<E> implements Iterator<E> { private final Iterator<? extends E> iter; public SuperTypeIterator(Iterator<? extends E> iter) { this.iter = iter; } @Override public E next() { return iter.next(); } // And similarly for the other methods of Iterator } 

This allows you to change the type of the return value as follows:

 Iterator<Plant> getPlantIterator() { return new SuperTypeIterator<Plant>( new MapleIterator() ); } 

This ensures complete type safety by creating a new object.

An alternative is to use an unchecked list:

 Iterator<Plant> getPlantIterator() { return (Iterator<Plant>) (Iterator<?>) new MapleIterator(); // Yes, the double cast is necessary to get it to compile. } 

This eliminates the need to create a wrapper object, but at the expense of security of all types.

0
source

All Articles