Java: Is it possible to say that a variable type must satisfy several inheritance / interface requirements

In some of the code I'm working with, I have an existing third-party API that implements things that extend from A (and possibly not directly, but through X and, possibly, also implementing many other interfaces).

Now, for the code I'm working on, I have an IB interface that provides additional capabilities to what A. offers. Since such code does have a requirement that the object passed to it extends A and also implements IB, but there is no way to declare it for my member variables that I can think of. But choosing A or IB leads to many castings.

I think if A had / had an IA interface, it would allow this, but I cannot change A, or for my IB implementations I do not need to extend A (third-party code uses A and takes a lot of control, persistence, networking, user interaction etc.).

class Z {
    private List<?what here?> items;
    /**The implementer of IB should know how to find the Z instance and call this.*/
    private void subscribe(? item) {
        items.add(item);
    }
    public void doSomethingWithItems() {
        ...code thats requires facilities from A and IB...
    }
+3
source share
4 answers

Use a common helper class whose type parameter allows you to use type intersection:

class Z {

    private static final class Wrapper<T extends A & IB> {

        private final T item;

        Wrapper(final T item) {
            this.item = item;
        }

        void doWork() {
            // code thats requires facilities from A and IB
        }
    }

    private List<Wrapper<?>> wrappers;

    private <T extends A & IB> void subscribe(T item) {
        wrappers.add(new Wrapper<T>(item));
    }
    public void doSomethingWithItems() {
        for (final Wrapper<?> wrapper : wrappers) {
            wrapper.doWork();
        }
    }

I gave a similar answer to this post: Java generic type mismatch in method signature

+2
source

You can specify the intersection of types:

<T extends A & IB>

The rules are that if one of the types is a class, it must be specified first.

I would type a class if you can:

class Z<T extends A & IB> {
    private List<T> items;

    private void subscribe(T item) {
        items.add(item);
    }
    public void doSomethingWithItems() {
        // the items are both A and IB
    }
}

Z, :

class Z {
    private List<A>items;

    private <T extends A & IB> void subscribe(T item) {
        items.add(item);
    }
    public void doSomethingWithItems() {
        // items are A, but if you want IB functionality you must cast.
        // the cast is safe if items are only added via subscribe()
    }
}
+3

, IB IA, ...

, Java . Java , , , IB.

, , API :

class Z {
    private List<A> items;

    private <B extends A & IB> void subscribe(B item) {
        items.add(item);
    }

    public void doSomethingWithItems() {
        for (A a : items) {
            IB b = (IB) a; // safe because we checked it on subscription
            // use features of A and IB
        }
    }
}

, . JVM, Ceylon, . , :

class Z() {

    List<A & IB> items;

    void subscribe(A & IB item) {
        items.add(item);
    }

    void doSomethingWithItems() {
        for (item in items) {
            // use features of A and IB
        }
    }
}
+2

You can create a new abstract class that implements IB with abstract methods and extends A. Then you can make all the classes you need, extend your new abstract class.

+1
source

All Articles