Java 抽象类中的类型安全问题

Java 抽象类中的类型安全问题,java,generics,static,abstract,Java,Generics,Static,Abstract,我最近开始用Java开发一个新项目,该项目将有一个本地数据库。作为设计的一部分,我创建了一个AbstractEntity类——它是数据库中一行(或潜在行)的对象表示 不过,在这个设计的早期,我遇到了一些问题,我想确保我没有走上一条糟糕的道路。我遇到的一个特殊方法是: public ArrayList retrieveEntities(String sql) { ArrayList ret = new ArrayList(); String query = "SELECT " +

我最近开始用Java开发一个新项目,该项目将有一个本地数据库。作为设计的一部分,我创建了一个AbstractEntity类——它是数据库中一行(或潜在行)的对象表示

不过,在这个设计的早期,我遇到了一些问题,我想确保我没有走上一条糟糕的道路。我遇到的一个特殊方法是:

public ArrayList retrieveEntities(String sql)
{
    ArrayList ret = new ArrayList();

    String query = "SELECT " + getColumnsForSelectStatement() + " FROM " + getTableName() + " WHERE " + sql;

    try (Connection conn = DatabaseUtil.createDatabaseConnection();
      Statement s = conn.createStatement();
      ResultSet rs = s.executeQuery(query))
    {
        while (rs.next())
        {
            AbstractEntity entity = factoryFromResultSet(rs);
            ret.add(entity);
        }
    }
    catch (SQLException sqle)
    {
        Debug.logSqlException(query, sqle);
    }

    return ret;
}
这种方法背后的思想是有一种从数据库中检索东西的通用方法,其中我唯一需要传递的是SQL的条件。就目前而言,它工作正常,但我有两个问题:

1)类型安全


我似乎无法在不导致编译器错误的情况下对该方法进行参数化
ArrayList
不好,我似乎无法理解
ArrayList第一点:如果将方法设为静态,那么使用多态性是没有意义的。多态性在运行时起作用,但使方法成为静态会迫使您在编译时指示动态类型,这是没有意义的


关于方法的返回类型,您可能希望首先将其设置为
ArrayList,我认为您正在重新发明轮子。已经存在多年,并证明非常有用

不过,它们不是防弹的。由于他们打算解决的问题相当困难(我的意思是),解决方案通常也有困难

为了以灵活的方式完成工作,一些orm会降低性能,而其他orm则会降低使用的简单性,等等。我的意思是,这里没有完美的解决方案

我想向您介绍我在不同项目中使用过的三种不同的ORM:

这里有许多比较和基准,深入讨论了这个主题

Hibernate是应用最广泛的,它健壮而强大,提供了很大的灵活性,如果使用得当,它的性能也很好。缺点是,它有一个陡峭的学习曲线,对于初学者来说有点复杂,一般来说,使用Hibernate的解决方案最终会永远使用Hibernate,因为很容易在不经意间让Hibernate潜入您的业务层

ActiveJDBC不是很流行,但它是Java的最佳ActiveRecord解决方案。如果你来自Ruby,这是你的选择。它的API非常流畅和富有表现力,使用它的代码非常容易阅读和维护。它非常简单,是一个非常精简的框架

E-Bean功能非常强大,其API流畅且富有表现力,并且该产品提供了自适应行为来动态优化查询。它使用简单,使用它的代码可读性好,易于维护

关于类型安全,我通常采用以下方法:

public class AbstractRepository<T extends AbstractEntity> {

    protected final Class<T> entityClazz;

    protected AbstractRepository() {
        Type type = this.getClass().getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) type;
        this.entityClazz = (Class<T>) paramType.getActualTypeArguments[0];
        // TODO exception handling
    }

    public List<T> list(String sql) { // retrieveEntities => very long name
        List<T> ret = new ArrayList<>();

        String query = "SELECT " + getColumnsForSelectStatement() + " FROM " + getTableName() + " WHERE " + sql;

        try (Connection conn = DatabaseUtil.createDatabaseConnection();
            Statement s = conn.createStatement();
            ResultSet rs = s.executeQuery(query)) {
            while (rs.next()) {
                T entity = factoryFromResultSet(rs);
                ret.add(entity);
            }
        } catch (SQLException sqle) {
            Debug.logSqlException(query, sqle);
        }

        return ret;
    }

    protected T factoryFromResultSet(ResultSet rs) {
        // Create new entity instance by reflection
        T entity = clazz.getConstructor().newInstance();

        // TODO exception handling 
        // Fill entity with result set data

        return entity;
    }
}
公共类抽象存储库{
受保护的最终类实体Lazz;
受保护的抽象存储库(){
类型类型=this.getClass().getGenericSuperclass();
ParameteredType paramType=(ParameteredType)类型;
this.entityClazz=(类)paramType.getActualTypeArguments[0];
//TODO异常处理
}
公共列表(字符串sql){//retrieveEntities=>非常长的名称
List ret=new ArrayList();
String query=“从“+getTableName()+”中选择“+getColumnsForSelectStatement()+”,其中“+sql”;
try(Connection conn=DatabaseUtil.createDatabaseConnection();
语句s=conn.createStatement();
结果集rs=s.executeQuery(查询)){
while(rs.next()){
T实体=factoryFromResultSet(rs);
ret.add(实体);
}
}捕获(SQLException sqle){
logSqlException(查询,sqle);
}
返回ret;
}
受保护的T factoryFromResultSet(ResultSet rs){
//通过反射创建新实体实例
T entity=clazz.getConstructor().newInstance();
//TODO异常处理
//用结果集数据填充实体
返回实体;
}
}
我声明了一个抽象存储库类,需要使用正确的参数类型对其进行扩展:

public class Person extends AbstractEntity {
}

public class PersonRepository extends AbstractRepository<Person> {
}

PersonRepository repo = new PersonRepository();
List<Person> people = repo.list("some SQL");
公共类Person扩展抽象实体{
}
公共类PersonRepository扩展了AbstractRepository{
}
PersonRepository repo=新建PersonRepository();
List people=repo.List(“一些SQL”);

我通常将生成实体的代码与实际实体的代码分开,否则实体最终会承担很多责任并做太多工作。然而,ActiveRecord方法通过让实体完成所有工作来解决这个问题,它是Java世界之外非常流行的选择。

旁注:您正在重新发明轮子(),请参阅无法转换类的原因。
public class Person extends AbstractEntity {
}

public class PersonRepository extends AbstractRepository<Person> {
}

PersonRepository repo = new PersonRepository();
List<Person> people = repo.list("some SQL");