Estoy codificando un generador de SQL basado en la reflexión de Java (está destinado a ser utilizado con genéricos en el futuro). Recibo un objeto como parámetro para generar el nombre de la tabla, los campos y los valores de campo (para operaciones de inserción y actualización), pero en mis clases de DAO estoy creando una instancia de un nuevo objeto vacío, que no se usará en ningún otro lugar del código. , solo obtenga esta información. ¿Hay alguna forma de lanzar algún tipo de objeto "fantasma", que no ocupará espacio en la memoria, para cumplir este propósito?

Esta es la clase responsable de generar el SQL:

public abstract class DynamicSQL
{
    public static final boolean NO_ID = false;
    public static final boolean WITH_ID = true;

    private Vector<Field> get_class_fields(Object obj, id_wanted)
    {
        Class<?> cls = obj.getClass();
        Vector<Field> fields = new Vector<>();

        while(cls != Object.class)
        {
            Field[] cls_flds = cls.getDeclaredFields();
            fields.addAll(Arrays.asList(cls_flds));

            cls = cls.getSuperclass();
        }
        // If the id is not wanted, it is removed here
        if(!id_wanted)
        {
            for(int i = 0; i < fields.size(); i += 1)
            {
                Field f = fields.get(i);
                if(f.getName().equals("id")) 
                                fields.remove(f);
            }
        }
        return fields;
    }

    private Vector<String> get_fields_names(Object obj, boolean id)
    {
        Vector<Field> fields = get_class_fields(obj, id);
        Vector<String> field_names = new Vector<>();

        for(Field f : fields)
        {
            field_names.add(f.getName());
        }
        return field_names;
    }

    private String get_table_name(Object obj) 
    {
        String[] class_name = obj.getClass().getName().toLowerCase().split("\\.");
        String table_name = class_name[class_name.length - 1];

        return table_name;
    }

    protected String select_sql(Object obj)
    {
        String table_name = get_table_name(obj);
        Vector<String> fields = get_fields_names(obj, WITH_ID);

        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;
    }

        //work in progress...
}

Esta es mi clase DAO:

public class CustomerDAO extends DynamicSQL implements IDAO<Customer>
{
    @Override
    public Vector<Customer> list_all() 
    {
        Vector<Customer> customers = new Vector<>();

        //Here I instantiate the object I'm willing to get rid of
        String sql = select_sql(new Customer.Builder().build(), DynamicSQL.WITH_ID);
        try
        {
            ResultSet rs = ConnectionFactory.get_instance().execute_query(sql);

            while(rs.next())
            {
                customers.add(new Cliente.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...
}

Todo funciona bien, pero estoy molesto con esa instanciación de objeto innecesaria. ¿Hay otra forma de hacerlo, o necesito crear una instancia de ese objeto de todos modos?

1
sandmann 9 oct. 2019 a las 16:02

1 respuesta

La mejor respuesta

En Java, nunca puede acceder directamente a los objetos. Lo que tiene son referencias a objetos (como punteros en C o C ++) que pueden se refiere a un objeto. Por lo tanto, diferentes clases y métodos pueden compartir objetos mediante el uso de diferentes referencias de objetos que hacen referencia (señalan) al mismo objeto. Si varias clases (o métodos) comparten objetos, en lugar de crear cada una un nuevo objeto para su uso exclusivo, no se utiliza espacio adicional para el segundo uso y los siguientes. Entonces, aunque no puede crear un objeto fantasma , puede hacer algo equivalente compartiendo objetos. Esto funciona mejor si los objetos son inmutables.

Si un método usa un objeto inmutable equivalente cada vez (que parece ser el caso de su método), puede ahorrar el costo de la creación del objeto cambiando el objeto para que sea un static objeto, por lo que el objeto se crea cuando la clase se carga y se comparte para todos los métodos posteriores ejecuciones.

Esto es lo que Collections.emptyList() El método hace:

Las implementaciones de este método no necesitan crear un objeto List separado para cada llamada.

3
Raedwald 10 oct. 2019 a las 06:00