I have this method to retrieve the objects which are instance of a given class:
public class UtilitiesClass {
public static final Collection<Animal> get(Collection<Animal> animals, Class<? extends Animal> clazz) {
// returns the Animals which are an instanceof clazz in animals
}
...
}
To call the method, I can do something like this:
Collection<Animal> dogs = UtilitiesClass.get(animals, Dog.class);
That is good, but I would also like to be able to call the method in these two ways:
Collection<Animal> dogs = UtilitiesClass.get(animals, Dog.class);
or
Collection<Dog> dogsTyped = UtilitiesClass.get(animals, Dog.class);
What I mean is that I want to be able to store result of the method in a Dog Collection or in an Animal one, because Dog.class
extends Animal.class
I was thinking in something like this:
public static final <T> Collection<T> get(Class<T extends Animal> clazz) {
// returns the Animals which are an instanceof clazz
}
But it does not work. Any hint?
Edit: Finally, using @Rohit Jain answer, this is the solution when you call to the UtilitiesClass method:
Collection<? extends Animal> dogsAnimals = UtilitiesClass.get(animals, Dog.class);
Collection<Dog> dogs = UtilitiesClass.get(animals, Dog.class);
Yes, you have to make the method generic. And the bounds should be given while declaring the type parameter:
public static final <T extends Animal> Collection<T> get(
Collection<Animal> animals, Class<T> clazz) {
}
But, while adding the animal
from animals
collection to a new Collection<T>
, you would have to cast it back to clazz
type. You would need Class#isInstance(Object)
method, and also Class#cast(Object)
method.
This is possible in Java 8 without using Class<T>
, however still may involve typecasting. A version that does not involve typecasting is also possible, but a bit more verbose:
public interface Animal {
public void makeSound();
}
public class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Waf");
}
}
public class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("Miauw");
}
}
public abstract class Utils {
@SuppressWarnings("unchecked")
public static <T_IN, T_OUT> Collection<T_OUT> getBySubType(Collection<T_IN> input, Predicate<T_IN> predicate) {
return input.stream()
.filter(predicate)
.map(element -> (T_OUT)element)
.collect(Collectors.toList());
}
public static <T_IN, T_OUT> Collection<T_OUT> getBySubTypeSafe(Collection<T_IN> input, Predicate<T_IN> predicate, Function<T_IN, T_OUT> function) {
return input.stream()
.filter(predicate)
.map(function)
.collect(Collectors.toList());
}
}
public class TestProject3 {
private void init() {
List<Animal> animals = new ArrayList<>();
animals.add(new Dog());
animals.add(new Cat());
animals.add(new Dog());
animals.add(new Cat());
animals.forEach(Animal::makeSound);
System.out.println();
Collection<Dog> dogs = Utils.getBySubType(animals, animal -> (animal instanceof Dog));
dogs.forEach(Animal::makeSound);
System.out.println();
Collection<Cat> cats = Utils.getBySubTypeSafe(animals, animal -> (animal instanceof Cat), animal -> (Cat)animal);
cats.forEach(Animal::makeSound);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
new TestProject3().init();
}
}
Output:
Waf
Miauw
Waf
MiauwWaf
WafMiauw
Miauw
What it does, is, in getBySubType
resp getBySubTypeSafe
:
Collection<T_IN>
. instanceof
predicate. T_OUT
, in our version use a Function<T_IN, T_OUT>
to explicitely safely cast it. Collection<T_OUT>
. The argument type should be generic wildcard to accept input collections of any subclass of Animal.
public static final <T extends Animal> Collection<T> get(
Collection<? extends Animal> animals, Class<T> clazz ) {
Collection<T> filteredAnimals = new ArrayList<T>();
for ( Animal animal : animals ) {
if ( clazz.isInstance( animal ) ) {
filteredAnimals.add( clazz.cast( animal ) );
}
}
return filteredAnimals;
}
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.