foo
foo

Reputation: 1018

Can I get a collection of object extending a class and implementing an interface?

There's not much to add to my question, basically:

class A {}
interface I {}

// how can I get a Set<> of object of type A that implements I?

I tried a few things <A & I>, <A extends I>, <? super A extends I> and a few other but didn't find anything that works, so I'm wondering if this is possible at all. If it isn't I'm curious about the reasoning behind it.

Thanks

Upvotes: 1

Views: 396

Answers (5)

meriton
meriton

Reputation: 70564

Java does not support intersection types, it only supports multiple bounds (as in extends A & I) when declaring type parameters. That is, we can not use a notation like A & I to denote the family of types that extend both A and I, but we can declare a type parameter <T extends A & I> to refer to a specific such type.

If the latter is what you want, a type parameter is a great fit. But if your collection should admit unrelated subtypes of A and I, no nice solutions seem to exist. My best idea is a hack like:

class AISetWrapper {
    Set<A> set = new HashSet<>();

    <T extends A & I> Set<T> getSet() {
        return (Set<T>) set; // unchecked cast that only works because generics are not reified
    }
}

which would allow us to write:

class AI1 extends A implements I { }

class AI2 extends A implements I { }

public static void main(String[] args) {
    AISetWrapper aiSet = new AISetWrapper();
    aiSet.get().add(new AI1()); // compiles
    aiSet.get().add(new AI2()); // compiles
    aiSet.get().add(new A()); // does not compile
    aiSet.get().add(new I() {}); // does not compile
}

Upvotes: 2

bcsb1001
bcsb1001

Reputation: 2907

You can write your own class:

public class MySet<E extends A & I> extends HashSet<E> {
    // blank
}

This will simply ensure that any instances of MySet will contain only objects that extend A and implement I.

Upvotes: 0

John B
John B

Reputation: 32949

I was able to do the following:

public class MyClass<T extends String & Iterable>{
    private Set<T> mySet;
}

And

public <T extends String & Iterable> void myFancyMethod(Set<T> mySet){}

However when I did

private Set<? extends String & Iterable>

I got a compile error of Syntax error on token "&". Seems that you can do the & syntax when declaring a type <T> but not for wildcards <? ...>.

A better discussion of this can be found at: Java Generics Wildcarding With Multiple Classes

Upvotes: 1

Aniket Thakur
Aniket Thakur

Reputation: 68915

// how can I get a Set<> of object of type A that implements I?

You cannot guarantee both in a single generic statement. You can do something like

public void addToSet(I iInstance) {
   if(iInstance instanceof A){  
   //logic to add to your set
    }
}

Upvotes: -1

laune
laune

Reputation: 31290

You'll have to make A implement I:

interface I {}
class A implements I {}

Set<A> setOfA;

Possible is alsp

class SubA extends A implements I { }
Set <SubA> setOfSubA;

Usage of a class A cannot make it change it's behaviour, as would be indicated by its sudden "implmentation" of I. Where should the implementations of the interface methods come from?

Upvotes: 1

Related Questions