rigon
rigon

Reputation: 1410

Types by argument?

I'm wondering if is possible pass types by argument in Java.

Let me explain better:

Suppose the next code

class Bee {
    // Class implementation
}

class Worker extends Bee {
    // Class implementation
}


class Queen extends Bee {
    // Class implementation
}

And now create a container with my bees objects

Vector<Bee> x=new Vector<Bee>();
// ...
for(i=0;i<10;i++)
    x.add(new Worker());
// ...
for(i=0;i<10;i++)
    x.add(new Queen());

Now I want create a generic method that iterates the vector and returns a set with a specific type of bees, Worker or Queen. How to do this?

EDIT

I tried

search(x,Worker.class);

static public <T extends Bee> Set<T> search(List<Bee> bees, Class<T> clazz){
    // ...
}

and I got an error reporting "The method search(List, Class) is no applicable for the arguments (Set, Class)". The problem is on 2nd argument because the types are incompatible.

Upvotes: 2

Views: 227

Answers (4)

Andreas Dolk
Andreas Dolk

Reputation: 114787

From your edit I see, you're still struggling with the implementation. Here is a working example:

public static void main(String[] args) {
    Collection<Bee> bees = new ArrayList<Bee>();
    bees.add(new Hive.Worker());
    bees.add(new Hive.Queen());
    Set<Queen> queens = getBeesOfOneType(bees, Queen.class);
}

private static <T extends Bee> Set<T> getBeesOfOneType(Collection<Bee> bees, Class<T> beeType) {
    Set<T> result = new HashSet<T>();
    for (Bee bee : bees) {
        if (beeType.isInstance(bee)) {
            // The following cast is safe. The previous if makes sure that
            // that bee can be cast to T at this place
            T beeTypeInstance = beeType.cast(bee);
            result.add(beeTypeInstance);
        }
    }
    return result;
}

There is still one Type safety warning and I'm pretty sure that this one can't be eliminated. The compiler doesn't now, that we select only the T type bees, so it has to warn us.

Upvotes: 5

matt b
matt b

Reputation: 139931

Use the Class as an argument to the method

public <T extends Bee> Set<T> filterBeesByType(List<Bee> bees, Class<T> clazz)

by the way, it is a good practice to refer to collection types by their interface (Set, List, etc) rather than implementation (Vector).

Upvotes: 4

Andreas Dolk
Andreas Dolk

Reputation: 114787

Use the instanceof operator:

public static Set<Queen> queensOnly(Collection<Bee> bees) {
  Set<Queen> queens = new HashSet<Queen>();
  for (Bee bee:bees) {
    if (bee instanceof Queen) {
      queens.add((Queen) bee);
    }
  }
  return queens;
}

Upvotes: 3

polygenelubricants
polygenelubricants

Reputation: 383776

You can use instanceof expression to test if a Bee is a Worker or a Queen. You can use this to filter your Vector<Bee> (or even better, a List<Bee>) according to the subtypes.

Guava also provides Iterables.filter(Iterable<?> unfiltered, Class<T> type) that you can use.

Upvotes: 5

Related Questions