【问题标题】:Is it possible to combine these methods? (Java Generics)可以结合这些方法吗? (Java 泛型)
【发布时间】:2019-02-01 17:57:24
【问题描述】:

我正在为大学做家庭作业,该作业不允许我更改课程的属性。我想出了以下用于搜索方法的代码,但我不禁注意到重复的代码。我需要建立两种搜索方法。一种搜索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();
}

【问题讨论】:

  • Person Module 是实现同一个接口,还是扩展同一个基类?
  • 不,他们没有。编辑。哎呀,他们有,但它不是我需要搜索的领域
  • 你能把课程放在你的问题中吗?如果你决定让它们实现一个通用接口,这会不会有问题?
  • 名称(和其他字段)是否有 getter 方法?
  • @rgettman 是的,我现在意识到确实有一个公共 getter getString() 是类中几个字符串字段的串联。其中一个组件是name,因此String.contains 方法将起作用。

标签: java class generics


【解决方案1】:

理想情况下,你让你的两个类实现相同的接口,比如NamedItem,它有一个函数getName(),它会简单得多,因为你让你的函数采用List&lt;? extends NamedItem&gt;。如果这不可能,您将必须提供 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);

您可以将它与任何属性一起使用,而不仅仅是名称。您只需将提取要匹配的String 的函数作为第三个参数传递即可。

【讨论】:

    【解决方案2】:

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

    <T extends Person & Module>
    

    但在这种情况下,T 必须同时扩展两者,所以它不是您要寻找的。​​p>

    要结合你的两个方法,类型必须共享一个公共接口,例如

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-30
      • 1970-01-01
      • 1970-01-01
      • 2022-01-26
      • 1970-01-01
      相关资源
      最近更新 更多