Reputation: 2316
I have a slightly odd issue with Java generics. Actually it might not be an issue at all and it might just me that I am trying to use generics incorrectly in design. I will not give the entire details of the application (it is irrelevant and boring).
I have created a small snippet that captures the essence of the problem.
There is a Producer interface which looks like this.
public interface Producer<P> {
public P produce();
}
There is an implementation of this interface which looks like this
public class IntegerProducer<P> implements Producer<P> {
@Override
public P produce() {
return (P)new Integer(10);
}
}
What I really need to do in the produce method is something like
if (P instanceOf Integer) return (P)new Integer(10);
else throw new Exception("Something weird happened in the client app");
Now of course the P instanceOf Integer won't work. But if you have got the essence of what I am trying to do, would you please share a solution.
Thanks for helping.
Clarification 1: The issue is not that I want to return Integer only. The issue is that in the function produce(), I need to check the type of generics used by the client program and change the behaviour of the function based on that. It is not that I want to restrict the type of generics used to a particular type of Object (where I could have used wildcards) but I need the function produce() to behave slightly differently based on the kind of Object used in the generics by the client code.
Upvotes: 3
Views: 57
Reputation: 328598
How about:
public class IntegerProducer implements Producer<Integer> {
@Override
public Integer produce() {
return 10;
}
}
Since your IntegerProducer
deals with Integer
s only, you don't need it to be generic. You can then write:
Producer<Integer> p = new IntegerProducer();
Integer i = p.produce();
EDIT
Following your comment, I think the only way would be to pass a class parameter:
public class Producer<T> {
public static void main(String[] args) throws InterruptedException {
Producer<Integer> t1 = new Producer<> ();
Producer<String> t2 = new Producer<> ();
System.out.println(t1.get(Integer.class)); //prints 10
System.out.println(t1.get(String.class)); //does not compile
System.out.println(t2.get(String.class)); //throws exception
}
public T get(Class<T> c) {
if (c == Integer.class) {
return (T) (Object) 10;
}
throw new UnsupportedOperationException();
}
}
Alternatively you can pass it in the constructor (strategy used for example by EnumSets and EnumMaps):
public class Producer<T> {
public static void main(String[] args) throws InterruptedException {
Producer<Integer> t1 = new Producer<> (Integer.class);
Producer<Integer> t1 = new Producer<> (String.class); //does not compile
Producer<String> t2 = new Producer<> (String.class);
System.out.println(t1.get()); //prints 10
System.out.println(t2.get()); //throws exception
}
private final Class<T> c;
public Producer(Class<T> c) {
this.c = c;
}
public T get() {
if (c == Integer.class) {
return (T) (Object) 10;
}
throw new UnsupportedOperationException();
}
}
That clearly clutters the code and I would personally reconsider the design to avoid that kind of situation.
Upvotes: 10