java泛型构造函数

发布于 2025-01-03 13:40:40 字数 1888 浏览 0 评论 0原文

我目前有以下代码,用于从数据库检索数据,然后创建一个User。这段代码在我的许多类中用于创建其他对象,例如NewsComments等...

它使用apache commons dbutils。

final ResultSetHandler<User> handler = new ResultSetHandler<User>() {

            @Override
            public User handle(ResultSet rs) throws SQLException {

                User user = null;
                if (rs.next()) {
                    user = new User();
                    user.setId(rs.getInt("id"));
                    user.setUsername(rs.getString("username"));
                    user.setPassword(rs.getString("password"));
                }
                return user;
            }
        };

        final User user = run.query(
                "SELECT id, username, password FROM users WHERE username = ? AND active = 2 LIMIT 1;", handler,
                username);

是否可以将 QueryRunner 包装在通用类中并重写查询方法,以便处理程序使用 ResultSet 实例化通用 T。我会确保任何 T 类型都有一个接受 ResultSet 的构造函数。

就像这样:

        public class QueryExecuter<T> extends QueryRunner {
    private ResultSetHandler<T> _handler;

    public QueryExecuter(){//The T type was for testing haha
        super();
        handler = new ResultSetHandler<T>() {

            @Override
            public T handle(ResultSet rs) throws SQLException {

                T object = null;
                if (rs.next()) {
                    object = new T(rs);
                }
                return object;
            }
        };
    }
}

我不知道你是否会理解,但我希望如此,问我是否需要更多细节或更好的解释。

编辑

我认为我可以使用 AbstractClass 而不是所有不同对象都会扩展的泛型类型,但似乎我无法编写抽象构造函数。我是否必须创建一个返回对象实例的静态方法,例如:

public abstract class DatabaseEntity {
    public static abstract DatabaseEntity create(ResultSet rs);//even this doesn't work...
}

I currently have the following code that retrieves data from the database and then create a User. This code is used in many of my classe to create other objects such as News, Commentsetc...

It uses apache commons dbutils.

final ResultSetHandler<User> handler = new ResultSetHandler<User>() {

            @Override
            public User handle(ResultSet rs) throws SQLException {

                User user = null;
                if (rs.next()) {
                    user = new User();
                    user.setId(rs.getInt("id"));
                    user.setUsername(rs.getString("username"));
                    user.setPassword(rs.getString("password"));
                }
                return user;
            }
        };

        final User user = run.query(
                "SELECT id, username, password FROM users WHERE username = ? AND active = 2 LIMIT 1;", handler,
                username);

Would it be possible to wrap the QueryRunner in a generic class and override the query method so the handler instanciate the generic T with the ResultSet. I would make sure any Ttype would ahve a constructor accepting a ResultSet.

Like so :

        public class QueryExecuter<T> extends QueryRunner {
    private ResultSetHandler<T> _handler;

    public QueryExecuter(){//The T type was for testing haha
        super();
        handler = new ResultSetHandler<T>() {

            @Override
            public T handle(ResultSet rs) throws SQLException {

                T object = null;
                if (rs.next()) {
                    object = new T(rs);
                }
                return object;
            }
        };
    }
}

I don't know if you'll understand, but I hope so, ask me if you want more details or a better explanation.

EDIT

I thought I could use a AbstractClass instead of the generic type that all of the differents objects would extends but it seems like I can't write an abstract constructor. Will I have to make a static method that return an instance of the object like:

public abstract class DatabaseEntity {
    public static abstract DatabaseEntity create(ResultSet rs);//even this doesn't work...
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

神也荒唐 2025-01-10 13:40:40

有可能吗?但这是个坏主意。

您可以这样做:

class ResultSetHandler<T> {
  ResultSetHandler<T>(Class<T> clazz) {
    this.clazz = clazz;
  }

  public T handle(ResultSet rs) throws SQLException {
    T object = null;
    if (rs.next()) {
      object = clazz.getConstructor(ResultSet.class).newInstance(rs)
    }
    return object;
  }
}

但是,混合域和数据库是一个坏主意。然而,更好的方法是定义一个基于结果集创建对象的抽象方法:

abstract class ResultSetHandler<T> {

  protected abstract T create(ResultSet rs);

  public T handle(ResultSet rs) throws SQLException {
    T object = null;
    if (rs.next()) {
      object = create(rs);
    }
    return object;
  }
}

然后,在您的实现类中,您只需要提供一个 create() 方法,而不需要处理自己设置结果,例如:

h = new ResultSetHandler<Person>() {
  protected Person create(ResultSet rs) {
    return new Person(rs.getString("name"));
  }
}

Possible, yes? But its a bad idea.

You could do:

class ResultSetHandler<T> {
  ResultSetHandler<T>(Class<T> clazz) {
    this.clazz = clazz;
  }

  public T handle(ResultSet rs) throws SQLException {
    T object = null;
    if (rs.next()) {
      object = clazz.getConstructor(ResultSet.class).newInstance(rs)
    }
    return object;
  }
}

Mixing domain and database is a bad idea, however. What would be better, however, would be to define an abtract method that creates the object based on the resultset:

abstract class ResultSetHandler<T> {

  protected abstract T create(ResultSet rs);

  public T handle(ResultSet rs) throws SQLException {
    T object = null;
    if (rs.next()) {
      object = create(rs);
    }
    return object;
  }
}

Then, in your implementing class, you only need to provide a create() method instead of handling the result set yourself, for example:

h = new ResultSetHandler<Person>() {
  protected Person create(ResultSet rs) {
    return new Person(rs.getString("name"));
  }
}

你可以做类似的事情(通过传递要创建的对象的类,并使用反射来调用其构造函数),但我会发现让 POJO 依赖于 JDBC 并且不仅知道它如何存储在数据库中是糟糕的设计,还包括用于加载它的查询中使用了哪些别名。

简而言之,User POJO 构造函数没有责任处理外部未知查询的结果集。

您可以设计一个 AbstractSingleEntityHandler 超类,它只包含

if (rs.next()) {

块,并将实际的实体创建委托给抽象方法,但您不会获得太多收益。

You could do something like that (by passing the class of the object to create, and use reflection to call its constructor), but I would find it bad design to have the POJO dependent on JDBC, and knowing not only how it's stored in database, but also which aliases have been used in the query used to load it.

In short, it's not the responsibility of the User POJO constructor to handle a result set of an external, unknown query.

You could design an AbstractSingleEntityHandler superclass which would just have the

if (rs.next()) {

block, and would delegate the actual entity creation to an abstract method, but you wouldn't gain much.

萌辣 2025-01-10 13:40:40

我认为在 Java 中不可能做到这一点。您无法在泛型中创建 T 的实例。 java 中的泛型并不像 C++ 中那样真正是模板,它们只是对象周围的语法糖,它删除了强制转换并引发编译时警告。

无法像 C# 那样约束 T 使其必须具有构造函数。

如果确实有必要,最好的选择是使用反射来解析适当的类,但即使这样,您也会遇到问题,因为在调用方法时您无法知道 T 的运行时类 - 此信息已从 java 字节码中剥离。因此,您只需将类传递给方法即可对其使用反射。无论如何,我不太确定这是一个好的设计理念。

I do not think it is possible to do this in Java. You cannot create an instance of T in a generic. Generics in java are not really templates as in C++, they are only syntax sugar around an object which removes the casts and induces compile time warnings.

There is no way like in C# to constrain T so that it must have a constructor.

Your best bet if this is really neccessary is to resolve the appropriate class using reflection, but even then you will run into problem since you cannot know the runtime class of T as the method is being invoked - this information is stripped from the java bytecode. So you are left with passing the class to the method in order to use reflection on it. And I'm not too sure this is a good design idea anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文