2

I want to defined a generic parameter, which should extend Map or Collection, but I don't know how to do it:

public <T> void test(T t) {}

I can write it as:

public <T extends Map> void test(T t) {}

or

public <T extends Collection> void test(T t) {}

But I don't know is it possible to let T extend Map or Collection in a single method.

Freewind
  • 193,756
  • 157
  • 432
  • 708
  • 6
    How would you use `t`, if you don't know if it is a `Map` or a `Colleciton`? – aioobe May 09 '12 at 08:43
  • 1
    Possible duplication (http://stackoverflow.com/questions/745756/java-generics-wildcarding-with-multiple-classes) and as aioobe mentioned it makes your implementation more dirty – Sridhar G May 09 '12 at 08:44

3 Answers3

5

Short answer: no.

What do you intend to do with the t parameter within the method? Since Map and Collection have only Object as their common supertype, the only methods you can call on t will be those on Object. (Even methods on both interfaces, such as size(), will be rejected by the compiler.)

With that in mind, is there any reason you can't overload the method in this case? That is, define one implementation for each desired parameter type:

public void test(Map<?,?> t) { ... }
public void test(Collection<?> t) { ... }

If you don't want to do that for whatever reason, then it seems that you could equally just declare the method to take Object and perform a run-time type check of the class. This is semantically equivalent since you'd have to cast to call Map or Collection-specific methods anyway, though it does mean that the type check is done at compile time instead of runtime. Java's type system doesn't let you express this union-type dependency though, so I don't see any other alternative.

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
3

No it is not possible, but you can create two separate methods:

public <T extends Map> void test(T t) {
  // do the map part
}

public <T extends Collection> void test(T t) {
  // do the collection part
}

If you want to mix them in a handling method you can also write it like this:

private void mixedTest(Object t) {
  if (t instanceof Map) {
    // map part
  } else if (t instanceof Collection) {
    // collection part
  } else {
    throw new RuntimeException("Unknown object");
  }
}

and call:

public <T extends Map> void test(T t) {
  mixedTest(t);
}

public <T extends Collection> void test(T t) {
  mixedTest(t);
}

But I'm not sure it will lead to a nice code anyway. I would stick with the first part with the different implementation for the different type of objects.

KARASZI István
  • 30,900
  • 8
  • 101
  • 128
3

What about

public <T extends Map> void test(Map t) {}

and

public <T extends Collection> void test(Collection t) {}

...and then let Java choose the correct one to use?

Jaco Van Niekerk
  • 4,180
  • 2
  • 21
  • 48