Java Generics, Tightly Bounded Parameter Type

I want to have a method that has a signature like method(T1 t1, T2 t2) such that T2 is -T1 and / or T1 is -T2. I do not need the case when T1 and T2 are both T, but not both of them. I want the maximum allowed type to be bounded from above by the highest of T1 or T2 in the inheritance tree. I am using Java 6.

Below is an attempt to show some desired use cases.

 class Experiment { static List genericList = new ArrayList(); static ArrayList arrayList = new ArrayList(); static class Test1 { } static class Test2 extends Test1 { } static class Test3 extends Test1 { } static <T> T experiment0(T expected, T actual) { return actual; } /** Almost works, but want arbitrary ordering. Cannot overload due to erasure. */ static <T, S extends T> S experiment1(T expected, S actual) { return actual; } private static void experimentDriver() { // good, allowed List l = experiment0(genericList, arrayList); // bad, allowed; want compile-time error Object o = experiment0(new String(), new Integer(0)); // good, allowed Test1 test1 = experiment1(new Test1(), new Test3()); String string = experiment1(new String(), new String()); List list = experiment1(genericList, new ArrayList()); // good, disallowed experiment1(new Test2(), new Test3()); experiment1(new Test3(), new Test2()); experiment1(new Integer(0), new String()); experiment1(new ArrayList(), new LinkedList()); // bad, disallowed; want either order experiment1(new Test3(), new Test1()); experiment1(new ArrayList(), genericList); } } 

I know that I can achieve something similar with a signature like experiment(Class<T> clazz, T expected, T actual) but this forces the programmer to explicitly specify the highest valid type when I would like it to be output in language.

Note that a closer solution cannot simply be overloaded because their erasures are the same.

I hope I have provided enough information to convey what I want. I understand that this may just not be possible in Java, but I hope this is doable. This is also my first question on this forum, so if I unknowingly violated any rules, I apologize in advance and appreciate your patience!

+8
java generics static-typing templating
source share
1 answer

This is too long for comment.

From the point of view of the compiler, a restriction that may be false is not a restriction at all and will not help it determine which types should be allowed in different parameter slots, or what you are allowed to do with them. Thus, the language (neither C # nor Java, by the way) has syntax for defining one way or another. The reason for allowing type restrictions is that it allows you to process the variable as if it were that type in the method body. Thus:

 public static <T extends Collection> void foo(T a) { System.out.println(a.size()); } 

It will compile and execute because all subclasses of Collection have a size() method. The problem is that <T extends S || S extends T> <T extends S || S extends T> (or any other compiled syntax) does not help.

For example, suppose we had this:

 public static <T extends List || S extends ArrayList> S bar(T a, S b) { // details } 

Is it possible to call b.removeRange(...) in this example? We have no idea, because S may not be an ArrayList . What about a.size() ? Again, we do not know, because T may not be a List . So this is no better than if we just said

 public static <T, S> S bar(T a, S b) {...} 

Adding that they may come from one another adds an extra level of complexity to this example.

+2
source share

All Articles