泛型方法在实例化方法中传递的泛型类型时返回列表

Generic method returning a List while instantiating the generic Type passed in the method

我已经苦苦挣扎了很长时间,并查阅了一些资源,试图理解我如何使用泛型来实现我想要实现的目标,但一直无法找到提供的示例我需要什么。

一些示例包括使用 Supplier 接口或建议使用通用 class 然后实例化它。

我想要实现的是指定我希望方法 return 的类型,同时在方法中实例化相同类型并将其添加到列表,然后 return 该列表。

提前致谢。非常感谢任何帮助

public List<Doctor> queryDoctor() {
    Statement statement = null;
    ResultSet results;

    try {
        statement = connection.createStatement();
        results = statement.executeQuery("SELECT * FROM " + TABLE_DOCTOR);

        List<Doctor> doctors = new ArrayList<>();
        while (results.next()) {
            Doctor doctor = new Doctor();
            doctor.setId(results.getInt(1));
            doctor.setUserName(results.getString(2));
            doctor.setPassword(results.getString(3));
            doctor.setPassword_salt(results.getString(4));
            doctor.setRole(results.getInt(5));
            doctors.add(doctor);

        }
        return doctors;
    } catch (SQLException e) {
        System.out.println("Query failed: " + e.getMessage());
        return null;
    } finally {
        try {
            if (statement != null) {
                statement.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

您需要传入 Function<ResultSet, T>:

<T> List<T> queryDoctor(Function<ResultSet, T> fn)

并在循环中使用它:

doctors.add(fn.apply(results));

此函数将创建适当的具体类型:

List<Doctor> doctors = queryDoctor(results -> {
       Doctor doctor = new Doctor();
        doctor.setId(results.getInt(1));
        doctor.setUserName(results.getString(2));
        doctor.setPassword(results.getString(3));
        doctor.setPassword_salt(results.getString(4));
        doctor.setRole(results.getInt(5));
        return doctor;
});

List<Nurse> nurses = queryDoctor(results -> {
       Nurse nurse = new Nurse();
       // ...
       return nurse;
});

听起来您正在尝试自己的简单 ORM 解决方案,您在其中提供一个带有 SQL 字符串和类型的方法,该方法加载结果然后实例化类型,将结果集映射到通过 setter 的对象字段。

如果是这样,你就是在重新发明轮子。

一个完整的解决方案是使用 Hibernate 或 Top Link 之类的 ORM 工具,但这可能 运行 在您可以走路之前。如果您更喜欢小步骤,请考虑使用 Spring 的 Jdbc 模板来处理大量样板代码。

更新

好的,我问您是否正在寻找一种方法,该方法采用结果集并将其映射到任意 class,您说是的。这应该做这样的事情:

public <T> List<T> map(ResultSet rs, Class<T> clazz) throws Exception {
    //// Build a list of columns that are in the resultset
    List<String> columns = new LinkedList<>();
    ResultSetMetaData metaData = rs.getMetaData();
    for(int i=0; i < metaData.getColumnCount(); i++) {
        columns.add(metaData.getCatalogName(i));
    }

    //// Create a list to hold all the beans we are going to create from the resultset 
    List<T> rows = new LinkedList<>();

    //// Iterate over each row in the resultset, creating beans for each row and setting the values 
    while(rs.next()) {
        //// Create a new instance of the class passed in (must have a no-args constructor) 
        T row = clazz.newInstance();

        //// Now for the magic. This bit is very noddy and ORM packages will do this much better 
        for(String col : columns) {
            //// For each column that is in the resultset, find the setter in the bean class 
            String columnValue = rs.getString(col);
            String mutator = "set"+capitalizeFirstCharacter(col);
            Method m = clazz.getMethod(mutator, String.class);
            //// Invoke the setter, passing in the value from the resultset 
            m.invoke(row, columnValue);
        }

        rows.add(row);
    }

    return rows;
}

private static String capitalizeFirstCharacter(String s) {
    return s.substring(0, 1).toUpperCase() + s.substring(1);
}

请注意,此代码不处理异常,仅适用于填充有字符串的结果集,并且仅处理具有要填充的字符串字段的 bean。一旦您开始尝试编写更复杂的代码来处理更复杂的类型和反射……您就是在重新发明 ORM。尽量不要那样做。