Is it possible to deduce a generic type from the generic type of a constructor parameter?

I was wondering if it is possible that the general type of one class is determined by the generic type of another object passed as a parameter?

I am working on a stream iterator, so that multiple threads can safely use the iterator through a list without two streams receiving the same object. It works well in the current form, but I think it can be done a little better.

import java.util.Iterator; public class AtomicIterator implements Iterator<Object> { private Iterator<?> it; public AtomicIterator(Iterable<?> iterable) { it = iterable.iterator(); } public Object next() { synchronized(it) { if(it.hasNext()) return it.next(); else return null; } } } 

Some of the code has been omitted, but this should be the idea. Currently, to get the next object, you are always forced to return a returned object that seems inefficient.

 ArrayList<String> someList = new ArrayList<String>; AtomicIterator it = new AtomicIterator(someList); String example = (String)it.next(); 

The problem is that it.next() returns an Object type, where I want to return a String type in this example

A simple solution is to give AtomicIterator its own generic type, which will lead to something like

 ArrayList<String> someList = new ArrayList<String>(); AtomicIterator<String> it = new AtomicIterator<String>(someList); String example = it.next(); 

However, this seems redundant to me, someList had its generic type explicitly defined as String , and I want AtomicIterator to AtomicIterator its generic type from the Iterable object that was given to it.

What I really want is something like this

 import java.util.Iterator; public class AtomicIterator implements Iterator<E> { private Iterator<E> it; public <E> AtomicIterator(Iterable<E> iterable) { it = iterable.iterator(); } public E next() { synchronized(it) { if(it.hasNext()) return it.next(); else return null; } } } 

And from there you can do something like

 ArrayList<String> someList = new ArrayList<String>(); AtomicIterator it = new AtomicIterator(someList); String example = it.next(); 

But, alas, this does not work, because the generic type E exists only in the constructor area.

Does anyone know a good clean way to do this?

+4
source share
3 answers

Add a generic type to AtomicIterator and (if running under Java 6) a static factory method, so it allows generic types by default

 public class AtomicIterator<T> implements Iterator<T> { private Iterator<T> it; public AtomicIterator(Iterable<T> iterable) { it = iterable.iterator(); } public static <T> AtomicIterator<T> create ( Iterable<T> iterable ) { return new AtomicIterator( iterable ) } public T next() { synchronized(it) { if(it.hasNext()) return it.next(); else return null; } } } 

Here is the usage:

 ArrayList<String> someList = new ArrayList<String>; AtomicIterator<String> it = AtomicIterator.create(someList); 
+6
source

The problem with your generic AtomicIterator is that the constructor itself is generic and has a generic type that is different from the typical type parameter of the class. <E> in public <E> AtomicIterator defines a different general parameter than the general parameter of the class, although both values ​​are E During my first attempt to compile it, I got a rather confusing error:

 AtomicIterator.java:8: incompatible types found : java.util.Iterator<E> required: java.util.Iterator<E> it = iterable.iterator(); ^ 

Decision. Let the general parameter of the Iterable<E> constructor use the general parameter of the class 'E', removing <E> right after public and adding it to the class, so the region of general type E is the whole class:

 public class AtomicIterator<E> implements Iterator<E> // ^ Added here 

...

 public AtomicIterator(Iterable<E> iterable) // ^ Remove here 
0
source

Java 7 Algorithm -

 AtomicIterator<String> it = new AtomicIterator<>(someList); ^ no need to repeat String here public class AtomicIterator<E> implements Iterator<E> public AtomicIterator(Iterable<E> iterable) 

If you do not want to explicitly write the full type of it , instead, let the compiler infer the type, for example.

 var it = new ...; // the type of `it` is inferred from right hand side 

Unfortunately, Java does not yet have this feature and will not have it for a while.

0
source

All Articles