我有一个抽象类、一些子类和抽象类的通用 DAO。
public abstract class Person { ... }
public class User extends Person { ... }
public class Client extends Person { ... }
public PersonDao <T extends Person> { ... }
我想在 PersonDao 中创建一个 select 方法来返回 Person 类的子对象。
public T select(int id) throws SQLException {
String sql = "SELECT * FROM person WHERE per_id=?";
PreparedStatement ps = con.preparedStatement(sql);
ps.setInt(1, id);
ResultSet rs = ps.executeQuery();
T t = null;
if(rs.next()) {
t = new T(); // Error line
t.setId(rs.getInt("per_id"));
t.setName(rs.getString("per_name"));
}
return t;
}
如何实例化通用子类并返回子对象?
最佳答案
new T()
不允许,因为 type erasure在 java 。无论如何,泛型的全部目的是确保编译时代码中的类型安全,而数据访问类不能确保这一点,因为数据库中的条目可能对应于 User
或 Client
。换句话说,SQL 语句和子类之间没有映射(请注意,这通常由 Hibernate 等 ORM 框架处理)。解决方案是在代码中提供额外的参数来准确指定结果类型。通常,Person
的每个子类都应该有自己的 DAO 实现(即 UserDao
和 ClientDao
),而 PersonDao
方法应该是抽象的,例如:
public abstract class PersonDao<T extends Person> {
abstract T select(int id);
...
}
public class UserDao extends PersonDao<User> {
public User select(int id) throws SQLException {
// Assuming there is a type column to differentiate between types of Person
String sql = "SELECT * FROM person WHERE per_id=? and type=?";
PreparedStatement ps = con.preparedStatement(sql);
ps.setInt(1, id);
ps.setString(2, User.class.getName());
ResultSet rs = ps.executeQuery();
User user = null;
if(rs.next()) {
user = new User();
user.setId(rs.getInt("per_id"));
user.setName(rs.getString("per_name"));
}
return user;
}
...
}
如果代码可以在父 PersonDao
中共享,因为它在两个实现中是相同的(在这种情况下,我不认为首先使用 PersonDao
泛型有什么意义,您可以让它返回一个 Person
而不是 T
),那么您可以在构造函数中传递该类:
public class PersonDao<T extends Person> {
private Class<T> type;
public PersonDao(Class<T> type) {
this.type = type;
}
public T select(int id) {
String sql = "SELECT * FROM person WHERE per_id=? and type=?";
PreparedStatement ps = con.preparedStatement(sql);
ps.setInt(1, id);
ps.setString(2, type.getName());
ResultSet rs = ps.executeQuery();
T t = null;
if(rs.next()) {
t = type.newInstance();
t.setId(rs.getInt("per_id"));
t.setName(rs.getString("per_name"));
}
return t;
}
...
}
旁注:您的代码片段没有显示 JDBC 资源是如何关闭的。确保在您的真实代码中执行此操作。
关于来自抽象类的 Java 通用子实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42423948/