5

having:

public <T extends Foo> int(T a, T b) { }

Allows me to pass in a different type in a and b, if both implement the Foo interface.

I think this would be better stated as:

public <T extends Foo, U extends Foo> int(T a, U b) { }

My question is: is there a way to achieve the first signature (that both a and b are the same type and that both implement the Foo interface)?

Pablo Fernandez
  • 103,170
  • 56
  • 192
  • 232
  • I think there is none – Maurice Perry May 02 '15 at 22:42
  • So you want an upper and lower bound on the allowed type? – Martin M J May 02 '15 at 22:49
  • I think you would have to relly on some pos validation. I would create an annotation `@SameType` and validate the types comming in some kind of interceptor. – Jorge Campos May 02 '15 at 22:51
  • possible duplicate of [Is it possible to specify both upper and lower bound constraints on type parameters in Java?](http://stackoverflow.com/questions/2530563/is-it-possible-to-specify-both-upper-and-lower-bound-constraints-on-type-paramet) – Martin M J May 02 '15 at 22:54
  • If you're trying to do this because two instances of the same implementation of Foo can interact with each other, but not with instances of different implementations of Foo, consider doing things the way Comparable does them. `Integer` implements `Comparable`, `Double` implements `Comparable`, and you can pass two `Integer`s or two `Double`s to `void foo(Comparable a, Comparable b)`, but you can't mix them. This also allows certain types of mixing that *should* be allowed, like passing `B` and `C` if both extend `A implements Comparable`. – user2357112 May 02 '15 at 23:15
  • Yeah, no, there's no foolproof way of doing this. If `A` extends `B`, then an `A` can _always_ be substituted for a `B`; that's what `extends` _means._ – Louis Wasserman May 03 '15 at 00:25

2 Answers2

0

The following is a bit ugly but works.

public class Main {

  static class Foo {}
  static class Bar extends Foo {}
  static class Baz extends Foo {}
  static <T extends Foo, S extends T> void foo(T a, S b) { }

  public static void main(String []args) {
      foo(new Foo(), new Foo()); // Compiles fine
      foo(new Bar(), new Bar()); // Compiles fine
      foo(new Bar(), new Baz()); // Compiler error Baz doesn't extend Bar
  }
}

This is a little different than what you want because it allows for the second parameter to subclass the first. This I think is OK because S is a T so it should be able to work wherever a T does.

Benjy Kessler
  • 7,356
  • 6
  • 41
  • 69
  • I thought of this too, but if `Baz` extends `Bar`, it will compile. – pathfinderelite May 02 '15 at 22:46
  • Noted the difference, deleted the comment. :) – Jorge Campos May 02 '15 at 22:48
  • 1
    foo(new Foo(), new Bar()) would compile though – Maurice Perry May 02 '15 at 22:49
  • 1
    Yeah I noted that in my response. I don't think there is anywhere in Java where a type is acceptable but a derived type is not. An instance of a derived type IS an instance of the base type and therefore will work. This is usually a desired feature. I think the OP was mostly worried about siblings being sent as parameters and not parent child. – Benjy Kessler May 02 '15 at 22:50
0

If you have control of the classes, you can do this

public static class Foo<T extends Foo<T>> {}
public static class Bar extends Foo<Bar> {}
public static class Baz extends Foo<Baz> {}
public static <T extends Foo<T>> void doSomething(T a, T b) {}

final Bar bar = new Bar();
final Baz baz = new Baz();
doSomething(bar, bar);  // Allowed
doSomething(bar, baz);  // Compile error

This is similar to how Enum types are defined. However, it allows the second parameter to be a subclass of the first.

pathfinderelite
  • 3,047
  • 1
  • 27
  • 30