在实例化方法中传递的泛型类型时返回List的通用方法

时间:2018-04-30 06:48:58

标签: java generics generic-list

我一直苦苦挣扎了很长一段时间,并且已经查看了一些资源,试图理解我如何使用泛型来获得我想要实现的目标,但却未能找到一个提供我的例子需要。

一些例子包括使用Supplier接口或建议使用泛型类然后实例化它。

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

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

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

2 个答案:

答案 0 :(得分:2)

您需要传递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;
});

答案 1 :(得分:0)

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

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

完整的解决方案是使用像Hibernate或Top Link这样的ORM工具,但可以在你走路之前运行。如果您更喜欢婴儿步骤,请考虑使用Spring的Jdbc模板来处理许多样板代码。

更新

好的,我问你是否正在寻找一个采用结果集并将其映射到任意类的方法,你说是的。这应该是这样的:

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

请注意,此代码不处理异常,仅适用于填充了Strings的结果集,并且只处理具有要填充的String字段的bean。一旦你开始尝试编写更复杂的代码来处理更复杂的类型和反射......你正在重新发明ORM。尽量不这样做。