4

我有这个方法来检索作为给定类的实例的对象:

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
    }
...
}

要调用该方法,我可以执行以下操作:

Collection<Animal> dogs = UtilitiesClass.get(animals, Dog.class);

这很好,但我也希望能够以这两种方式调用该方法:

Collection<Animal> dogs = UtilitiesClass.get(animals, Dog.class);

或者

Collection<Dog> dogsTyped = UtilitiesClass.get(animals, Dog.class);

我的意思是我希望能够将方法的结果存储在狗集合或动物集合中,因为Dog.class扩展Animal.class

我在想这样的事情:

public static final <T> Collection<T> get(Class<T extends Animal> clazz) {
    // returns the Animals which are an instanceof clazz
}

但它不起作用。有什么提示吗?

编辑:最后,使用@Rohit Jain 回答,这是调用 UtilitiesClass 方法时的解决方案:

Collection<? extends Animal> dogsAnimals = UtilitiesClass.get(animals, Dog.class);
Collection<Dog> dogs = UtilitiesClass.get(animals, Dog.class);
4

3 回答 3

6

是的,你必须使方法通用。并且应该在声明类型参数时给出边界:

public static final <T extends Animal> Collection<T> get(
                   Collection<Animal> animals, Class<T> clazz) {
}

但是,在将animalfromanimals集合添加到 newCollection<T>时,您必须将其转换回clazz类型。你需要Class#isInstance(Object)方法,也需要Class#cast(Object)方法。

于 2014-02-26T16:53:12.540 回答
3

这在 Java 8 中是可能的,无需使用Class<T>,但仍可能涉及类型转换。不涉及类型转换的版本也是可能的,但有点冗长:

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();
    }
}

输出:

哇哇哇
哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇
哇哇哇
哇哇哇

哇哇哇
_

妙妙
妙妙

它的作用getBySubTypegetBySubTypeSafe

  • 获取作为输入Collection<T_IN>
  • 根据instanceof谓词过滤所有内容。
  • 在一个版本中将其转换为T_OUT,在我们的版本中使用 aFunction<T_IN, T_OUT>来明确地安全地转换它。
  • 返回Collection<T_OUT>.
于 2014-02-27T09:41:06.497 回答
0

参数类型应该是通用通配符,以接受 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;
}
于 2014-02-27T10:18:31.053 回答