简体   繁体   English

来自抽象类的Java通用子实例

[英]Java generic child instance from abstract class

I have a abstract class, some childs and a generic DAO to the abstract class. 我有一个抽象类,一些孩子和抽象类的通用DAO。

public abstract class Person { ... }
public class User extends Person { ... }
public class Client extends Person { ... }
public PersonDao <T extends Person> { ... }

I want to make a select method in PersonDao to return a child object of class 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;
}

How can I instantiate the generic child class and return a child object? 如何实例化泛型子类并返回子对象?

You cannot do this in Java because of Type Erasure . 由于Type Erasure,你无法在Java中执行此操作。 You can see this post to solve your problem. 你可以看到这篇文章来解决你的问题。 Basically, you have to provide the class that you want to obtain. 基本上,您必须提供要获取的类。

new T() is not allowed due to type erasure in Java. 由于Java中的类型擦除 ,不允许使用new T() Anyway, the whole purpose of generics is to ensure type safety in your code at compile time, and your data access class does not ensure that, because that entry in the database could correspond to either a User or a Client . 无论如何,仿制药的整个目的是要确保在你的代码在编译时类型安全,和你的数据访问类不保证,因为在数据库中的条目可以对应到任何一个UserClient In other words, there is no mapping between the SQL statement and the subclass (note that this is normally handled by ORM frameworks such as Hibernate). 换句话说,SQL语句和子类之间没有映射(请注意,这通常由ORM框架(如Hibernate)处理)。 The solution is to provide additional parameters in the code that specifies exactly the result type. 解决方案是在代码中提供准确指定结果类型的其他参数。 Typically, each child subclass of Person should have its own DAO implementation (ie a UserDao and a ClientDao ), while the PersonDao method should be abstract, eg: 通常, Person每个子类都应该有自己的DAO实现(即UserDaoClientDao ),而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;
    }

    ...
}

If the code can be shared in the parent PersonDao because it is the same in both implementation (in which case I don't see the point of having the PersonDao generic in the first place, you could just make it return a Person instead of T ), then you can pass the class in the constructor: 如果代码可以在父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;
     }

     ...
}

Side note: Your code snippet does not show how JDBC resources are being closed. 附注:您的代码段未显示如何关闭JDBC资源。 Make sure to do that in your real code. 确保在您的真实代码中执行此操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM