是否可以结合使用这些方法? (Java泛型)

时间:2019-02-01 17:57:24

标签: java class generics

我正在为大学的家庭作业不允许我改变类的属性。我为搜索方法提出了以下代码,但我不禁注意到重复的代码。我需要建立两种搜索方法。一种搜索ArrayList<Person>,另一种搜索ArrayList<ModulePersonModule都具有String name属性。

public static <T extends Person> ArrayList<T> findPerson(List<T> list, String query) {
    ArrayList<T> matching = new ArrayList<>();
    list.forEach(s -> {
        if (s.name.contains(query)) matching.add(s);
    });
    return matching;
}

public static <T extends Module> ArrayList<T> findModule(List<T> list, String query) {
    ArrayList<T> matching = new ArrayList<>();
    list.forEach(s -> {
        if (s.name.contains(query)) matching.add(s);
    });
    return matching;
}

是否可以在不更改类结构的情况下组合这些方法?我想沿着这些线路的东西,但它仍然不似乎工作:(在方法签名不同的类型参数)

public static <T extends Person, Module> ArrayList<T> findModule(List<T> list, String query) {
    ArrayList<T> matching = new ArrayList<>();
    list.forEach(s -> {
        if (s.name.contains(query)) matching.add(s);
    });
    return matching;
}

编辑:以下是这些类:

public abstract class Person extends TableItem {

public String name, famName, street, zip, city;
public String[] data = new String[7];

...
}

public class Module extends TableItem {

private Manager manager;
public String[] data = new String[5];
public String name, nr, profID, semester, part;
public ArrayList<String> participants;

...
}

public abstract class TableItem {

public abstract String getString();
public abstract void updateData();
}

2 个答案:

答案 0 :(得分:3)

理想地,您使两个类都实现相同的接口,例如将具有功能NamedItem的{​​{1}},因为要使函数采用getName(),所以它要简单得多。如果无法做到这一点,则必须提供List<? extends NamedItem>来确定要匹配的Function属性。

String

然后您可以像使用它一样

public static <T> List<T> find(List<T> list, String query, Function<T, String> keyExtractor) {
    return list
        .stream()
        .filter(s -> keyExtractor.apply(s).contains(query))
        .collect(Collectors.toList());
}

您可以将其与任何属性一起使用,而不仅仅是名称。您只需传递提取要匹配的List<Person> matchingPersons = find(allPersons, query1, Person::getName); List<Module> matchingModules = find(allModules, query1, Module::getName); 作为第三个参数的函数即可。

答案 1 :(得分:2)

为泛型类型指定多个基本类型的唯一方法是使用&语法:

<T extends Person & Module>

但是在这种情况下,T必须同时扩展两者,所以这不是您要的内容。

要结合使用这两种方法,这些类型必须共享一个公共接口,例如

public interface Named {
    String getName();
}

现在,如果PersonModule都扩展/实现了Named接口,则您的方法可以是:

public static <T extends Named> ArrayList<T> findNamed(List<T> list, String query) {
    return list.stream().filter(s -> s.getName().contains(query))
               .collect(Collectors.toCollection(ArrayList::new));
}