简体   繁体   中英

Java Generic Type extend multiple classes

How can the type for a generic class extend multiple classes? For example, say I have I generic that I want to be able to take objects that are subclasses of Melons or Berries, but not objects that are subclasses of other subclasses of Fruits? I was thinking something like

public class MyGeneric<T extends Melons & Berries>

but this does not work as an interface is expected after the ampersand, not a class. Additionally, online I saw the suggestion to make an interface and have T implement the interface, however I do not understand how to make an interface that specifies classes that can be accepted by a generic.

& means and . T extends Melons & Berries means that T must be some type that extends both . You evidently want it to mean or . It doesn't. And <T extends Melons | Berries> <T extends Melons | Berries> is not legal java syntax. For good reason - that would be useless.

You may think: Wait, you can't extend 2 things. Yes, you can - extends in generics refers solely to supertypes; it's like a combination of extends and implements .

For example:

void test(List<? extends Serializable & CharSequence> items) {
}

can be invoked by passing a List<String> . That's because String is a subtype of Serializable , and also a subtype of CharSequence .

The 'point' of this is that when you get an element from this list, you can treat it as either. Because it's and - it's a list of both.

There is no way in java to say: "I want to accept a list of Berries, or a list of melons, but not a list of Apples". The reason there's no way to say that, is because its useless:

  • If there's a thing you can do to both melons and berries but not bananas, then whatever it is will have to be defined in an interface of sorts. Perhaps Melons and Berries both implement 'SeededFruit', and Banana doesn't. In that case, just write List<? extends SeededFruit> List<? extends SeededFruit> isntead.
  • If you just want to use aspects of melons and berries that are shared by all fruit (also bananas), just write List<? extends Fruit> List<? extends Fruit> - why put up arbitrary restrictions?
  • If you want to write if (x instanceof Melons) doThing1; else if (x instanceof Berries) doThing2; if (x instanceof Melons) doThing1; else if (x instanceof Berries) doThing2; - java isn't 'meant' for that. There are tons of things java doesn't have that would be really convenient if everybody wrote code like that. But java doesn't have that, will not have that, folks don't usually write their java code like that. Usually if someone does, they're writing very 'bad' code, in the sense that it is overcomplicated and/or hard to maintain and/or hard to adopt in the face of changing requirements, and needlessly so: You could write it differently and avoid those traps.

The way I would do is to group the classes using an interface. Then I use the interface to define the generic class. See below:

interface ForGenerics { }

class Fruit { }
class Melon extends Fruit implements ForGenerics {}
class Berry extends Fruit implements ForGenerics {}
class Apple extends Fruit {}
class MyGeneric<T extends ForGenerics> { }

public class Main{
    public static void main(String[] args) {
        MyGeneric<Melon> a;
        MyGeneric<Berry> b;
        
        // can't make MyGeneric of Apple
        //  MyGeneric<Apple> c;  
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM