我正在尝试为JDBC创建一个通用行映射器。
我最初的尝试看起来是:
public class GenericRowMapper<T> implements RowMapper<T> {
private final Class<?> clazz;
public GenericRowMapper(T instance) {
this.clazz = instance.getClass().getComponentType();
}
@Override
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
System.out.println("field name : " + f.getName() + " , type : " + f.getType());
}
try {
return (T) clazz.getConstructor().newInstance();
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
}但是在构造函数中,getComponentType()返回null,因此clazz = null;和我无法取得任何进展。
我做错了什么?
发布于 2022-06-20 14:03:22
我做错什么了?
许多新手程序员都犯了一个错误(还有一些专家!)
--您没有阅读文档。
如果您这样做了,您可能已经注意到getComponentType()的文档告诉您它返回数组的组件类型。
假设,比方说,Class<?> c = String[].class,我可以打电话给c.getComponentType(),然后把String.class找回来。或者new String[10].getClass().getComponentType()也会给我同样的东西。
显然,您是在一个不代表数组类型的类上调用.getComponentType(),因此,您将得到null。
做得对
你的代码有点混乱。T是一个类型变量,因此,接受T instance的参数意味着您必须提供它的实际实例,也就是说,如果您有一个将一行映射为字符串的RowMapper,则必须提供一个字符串,这是没有意义的。想必你真正想要的是arg,而不是Class<T>,在这种情况下-瞧,这就是你的类。首先,不需要在它上调用.getClass()或.getComponentType()。如果您确实打算让此方法要求首先传递一个实际实例,那么.getClass()将是您想必想要的方法,但我认为这是行不通的:.getClass()总是给出实际的类型,即对类型列表的变量调用.getClass()永远不会返回List.class --它可能会返回ArrayList.class或实现List的某个匿名内部类。
您的代码的其余部分也类似地混淆了。
.getDeclaredFields()只返回类定义本身中的字段,而不是任何父类(其字段与任何其他类的实例一样多)--再一次,阅读文档来找出这一点。
“打印堆栈跟踪,返回null”是非常愚蠢的异常处理。正确的‘我还不关心它’异常处理程序是throw new RuntimeException("unhandled", e); -更短,更好。没有理由不这样做。如果必须的话,可以修复IDE的模板。
还没有准备好使用现代java
许多现代的java (特别是包括record特性)都有一个不可变的类,因此您不能“设置”一堆字段,并且不会有一个无参数构造函数( .getConstructor()会得到它,因此.getConstructor()会失败)。相反,构造函数本身接受所有的args;因此,您对字段不感兴趣,而是对构造函数的参数感兴趣。除非有多个参数,而且类(必要的)不包含参数的名称。
https://stackoverflow.com/questions/72688138
复制相似问题