Java中能否用不占内存的“幽灵”对象实现反射式SQL生成?
如何避免SQL生成器中无意义的对象实例化?
Great question! 你完全没必要创建那个仅用于反射的空对象——我们可以直接基于Class类型来实现所有反射操作,彻底规避这种无意义的内存占用。核心思路是:反射获取类的字段、类名等元信息,只需要Class对象就足够了,根本不需要实例化对象。
1. 重构DynamicSQL类,让方法依赖Class而非Object
我们需要把原来所有依赖Object obj的方法,改成直接接收Class<?> cls参数,跳过对象实例化的步骤。以下是修改后的核心代码:
public abstract class DynamicSQL { public static final boolean NO_ID = false; public static final boolean WITH_ID = true; // 重构:直接接收Class参数,不再需要Object实例 private Vector<Field> get_class_fields(Class<?> cls, boolean id_wanted) { Vector<Field> fields = new Vector<>(); while(cls != Object.class) { Field[] cls_flds = cls.getDeclaredFields(); fields.addAll(Arrays.asList(cls_flds)); cls = cls.getSuperclass(); } // 优化移除id的逻辑:用Iterator避免索引错位 if(!id_wanted) { Iterator<Field> iterator = fields.iterator(); while(iterator.hasNext()) { Field f = iterator.next(); if(f.getName().equals("id")) { iterator.remove(); } } } return fields; } // 同样改为接收Class参数 private Vector<String> get_fields_names(Class<?> cls, boolean id) { Vector<Field> fields = get_class_fields(cls, id); Vector<String> field_names = new Vector<>(); for(Field f : fields) { field_names.add(f.getName()); } return field_names; } // 重构为接收Class参数 private String get_table_name(Class<?> cls) { String[] class_name = cls.getName().toLowerCase().split("\\."); String table_name = class_name[class_name.length - 1]; return table_name; } // 新增:基于Class生成SELECT SQL的方法 protected String select_sql(Class<?> entityClass, boolean includeId) { String table_name = get_table_name(entityClass); Vector<String> fields = get_fields_names(entityClass, includeId); String sql = "SELECT "; for(int i = 0; i < fields.size(); i += 1) { sql += fields.get(i); if(i < fields.size()-1) sql += ", "; } sql += " FROM " + table_name; return sql; } // 保留原有方法作为兼容(可选) protected String select_sql(Object obj) { return select_sql(obj.getClass(), WITH_ID); } protected String select_sql(Object obj, boolean includeId) { return select_sql(obj.getClass(), includeId); } // work in progress... }
2. 修改CustomerDAO的调用方式,直接传入Class对象
现在你可以彻底抛弃空对象的实例化,直接传入Customer.class即可:
public class CustomerDAO extends DynamicSQL implements IDAO<Customer> { @Override public Vector<Customer> list_all() { Vector<Customer> customers = new Vector<>(); // 直接传入Class,无需实例化对象! String sql = select_sql(Customer.class, DynamicSQL.WITH_ID); try { ResultSet rs = ConnectionFactory.get_instance().execute_query(sql); while(rs.next()) { customers.add(new Customer.Builder() .id(rs.getLong("id")) .nome(rs.getString("nome")) .endereco(rs.getString("endereco")) .telefone(rs.getString("telefone")) .build() ); } } catch(SQLException e) { e.printStackTrace(); } return customers; } // other method overrides and implementation... }
3. 进阶:利用泛型自动获取Class(适配未来计划)
既然你未来打算支持泛型,可以进一步优化DAO类,让它自动获取泛型参数的Class,避免每个DAO都手动写Xxx.class。比如新增一个基类:
public abstract class BaseDAO<T> extends DynamicSQL implements IDAO<T> { protected final Class<T> entityClass; @SuppressWarnings("unchecked") public BaseDAO() { // 通过反射获取泛型参数的Class ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); this.entityClass = (Class<T>) type.getActualTypeArguments()[0]; } // 封装通用的list_all方法 @Override public Vector<T> list_all() { Vector<T> entities = new Vector<>(); String sql = select_sql(entityClass, DynamicSQL.WITH_ID); try { ResultSet rs = ConnectionFactory.get_instance().execute_query(sql); while(rs.next()) { entities.add(buildEntity(rs)); } } catch(SQLException e) { e.printStackTrace(); } return entities; } // 子类需实现:从ResultSet构建实体对象 protected abstract T buildEntity(ResultSet rs) throws SQLException; }
然后CustomerDAO可以简化成:
public class CustomerDAO extends BaseDAO<Customer> { @Override protected Customer buildEntity(ResultSet rs) throws SQLException { return new Customer.Builder() .id(rs.getLong("id")) .nome(rs.getString("nome")) .endereco(rs.getString("endereco")) .telefone(rs.getString("telefone")) .build(); } // other method overrides and implementation... }
这样不仅完全消除了空对象,还让DAO代码更通用,完美适配你未来支持泛型的计划!
总结
这种改造方式的核心优势:
- 彻底消除了无意义的对象实例化,节省内存开销
- 代码更清晰,直接表达了“基于类元信息生成SQL”的意图
- 为未来泛型支持打下了坚实的基础
内容的提问来源于stack exchange,提问作者hcotta
相关产品推荐
相关产品推荐

