435

I want to have a Class object, but I want to force whatever class it represents to extend class A and implement interface B.

I can do:

Class<? extends ClassA>

Or:

Class<? extends InterfaceB>

but I can't do both. Is there a way to do this?

davneetnarang
  • 436
  • 1
  • 4
  • 15
Alex Beardsley
  • 20,988
  • 15
  • 52
  • 67

2 Answers2

694

Actually, you can do what you want. If you want to provide multiple interfaces or a class plus interfaces, you have to have your wildcard look something like this:

<T extends ClassA & InterfaceB>

See the Generics Tutorial at sun.com, specifically the Bounded Type Parameters section, at the bottom of the page. You can actually list more than one interface if you wish, using & InterfaceName for each one that you need.

This can get arbitrarily complicated. To demonstrate, see the JavaDoc declaration of Collections#max, which (wrapped onto two lines) is:

public static <T extends Object & Comparable<? super T>> T
                                           max(Collection<? extends T> coll)

why so complicated? As said in the Java Generics FAQ: To preserve binary compatibility.

It looks like this doesn't work for variable declaration, but it does work when putting a generic boundary on a class. Thus, to do what you want, you may have to jump through a few hoops. But you can do it. You can do something like this, putting a generic boundary on your class and then:

class classB { }
interface interfaceC { }

public class MyClass<T extends classB & interfaceC> {
    Class<T> variable;
}

to get variable that has the restriction that you want. For more information and examples, check out page 3 of Generics in Java 5.0. Note, in <T extends B & C>, the class name must come first, and interfaces follow. And of course you can only list a single class.

jshd
  • 187
  • 3
  • 9
Eddie
  • 53,828
  • 22
  • 125
  • 145
  • But why do I have to cast the object to T when returning it? –  Nov 18 '11 at 15:48
  • @BernhardV: You need to provide more information before I can answer it. In what situation do you need to cast? – Eddie Dec 07 '11 at 00:04
  • 107
    This is helpful. It's worth mentioning that the class _must_ come first, you cannot say ''. – EricS Feb 28 '12 at 21:55
  • You can also separate by commas but only the classes. – JungJoo Sep 23 '13 at 14:56
  • 6
    How do you do the same for T should either extend a class OR implement an interface? – Ragunath Jawahar Nov 12 '13 at 03:23
  • 2
    @RagunathJawahar: You cannot get too open-ended about this. You have to have some boundaries, and one of them is knowing in advance where you'll have interfaces and where you'll have classes, and how you'll use inheritance. You pretty much have to know for a type parameter if it will be a class or an interface. – Eddie Nov 22 '13 at 23:42
  • @Eddie, you're right. I figured this out. It is different for different use cases. I ended up solving mine using a generic method. The base class specifies bounds using a super class. And one of the generic method narrows that down by extending a base class and an interface. – Ragunath Jawahar Nov 25 '13 at 10:57
  • what would be the use of the `T extends Object` part ? – njzk2 Dec 24 '13 at 20:41
  • @JungJoo : in which case could there be several classes, and why would they be separated by a coma ? – njzk2 Dec 24 '13 at 20:42
  • @njzk2: Check the link I made to "To preserve binary compatibility" in my answer. It explains why the "T extends Object" part is there. – Eddie Jan 03 '14 at 16:19
  • 4
    The first line of your answer says to "have your wildcard look something like this." There is no `?` in that expression, so is it really a "wildcard"? I ask because I can't get the whole "extending two things at once" concept to work when the type parameter really is a wildcard. – The111 Jan 11 '15 at 08:29
  • 2
    Yeah, it's not really a wildcard and you can't do what the OP asked for with a wildcard. You **can** do what the OP wanted, effectively, just not with a wildcard. – Eddie Apr 16 '15 at 23:48
  • Funny, but what you cannot do (seemingly) is , because 1) type parameter must go last in "&", 2) even in that form it yields "unexpected type". – Maksim Gumerov Jun 07 '18 at 07:43
  • Strange syntax. – Alex78191 Nov 13 '19 at 19:22
  • I'm looking for 2 level of extend here. `class GrandSon extends Child`, `class GrandDaughter extends Child`, `class Child extends Parent`. How do I declare `GrandChildrenTask>`. Note that Child and its subclasses are unknown, only Parent is available in library. – Kiran A B May 01 '20 at 10:46
  • @KiranAB Are you saying `T extends from something that extends Parent`. In that case, since inheritance is transitive, all you need is `T extends Parent`. Also, you cannot distinguish the level of inheritance. So here, both `Child` and `GrandSon` are equally valid. – Sourav Kannantha B Aug 11 '21 at 12:47
  • @KiranAB If you really want only `GrandSon` to be passed and not `Child`, then there must be something special in `GrandSon`. In that case, you can just specify it like `T extends Parent & Grandness`. – Sourav Kannantha B Aug 11 '21 at 12:48
  • “Actually, you can do what you want.”—Why not edit this opening line to clarify that you *can’t* do it with `?`? Like people have pointed out before. I thought that I could just go ahead with `?` but then got really confused. Only the next answer here told me that `?` won’t work for some reason. Also the “the class name must come first” limitation should be mentioned in the first paragraph, in my opinion. – Guildenstern Jul 03 '22 at 11:31
21

You can't do it with "anonymous" type parameters (ie, wildcards that use ?), but you can do it with "named" type parameters. Simply declare the type parameter at method or class level.

import java.util.List;
interface A{}
interface B{}
public class Test<E extends B & A, T extends List<E>> {
    T t;
}
Aleksandr Dubinsky
  • 22,436
  • 15
  • 82
  • 99
user2861738
  • 321
  • 2
  • 2
  • 6
    Why aren't wildcards allowed? i.e. I don't see why this shouldn't be valid: ArrayList extends ClassA & InterfaceB> list; And then if you pulled an element out of the list, you could assign it to a variable of type ClassA or of type InterfaceB – Mark Apr 10 '17 at 22:27
  • Replacing the wildcard with a variable is a great technique! But it doesn't always work. For example, Java does not allow names type variables in annotation value types, while it does allow wildcards. – sigpwned Jul 22 '17 at 13:18