I’m building an Android app, and have set up a base DBObject class to ease table interactions. The DBObject constructor sets up a cursor and passes it to virtual method loadRecord, which the subclass overrides to load its own attributes. The attributes are all correct according to the Log.i call at the end of loadRecord, but once the calling method gets the object back, all of the data members have the default defined in the class declaration rather than the loaded values (strings are null, floats are 0.00, etc).
public abstract class DBObject {
....
public DBObject(DBHelper dbh, String table_name, int _id){
// loads an existing DBObject from the database by id
this.dbh = dbh;
this.TABLE_NAME = table_name;
this.id = _id;
setupDbr();
String sql = String.format("select * from %s where _id=%d", TABLE_NAME, id);
Cursor cur = dbr.rawQuery(sql, null);
if (cur.getCount() == 0){
throw new RowDoesNotExistException(id);
} else if (cur.getCount() > 1){
throw new RowDoesNotExistException("Record is not unique.", id);
}
cur.moveToFirst();
loadRecord(cur);
}
....
abstract void loadRecord(Cursor cur);
this constructor calls the overridden loadRecord, which looks like this in a subclass:
public class Expense extends DBObject{
public String date = null;
public String supplier = null;
public String description = null;
public float amount = 0.00f;
public boolean receipt = false;
public Expense(DBHelper dbh, String _id){
super(dbh, DBHelper.EXPENSE_TABLE, _id);
...
@Override
void loadRecord(Cursor cur){
id = cur.getInt(0);
date = cur.getString(1);
supplier = cur.getString(2);
description = cur.getString(3);
amount = cur.getFloat(4);
receipt = (cur.getInt(5) == 1);
Log.i("net.bradmont.reimburseit", String.format("%d, %s, %s, %s", id, date, supplier, description));
}
Members that are set in the DBObject constructor remain as they are set. I am at a total loss on this….
Thanks in advance!
The problem is that you’ve got instance variable initializers:
The initializers will be executed after the superclass constructor executes, and before the body of the subclass constructor executes. This is one of the problems with calling overridden methods in a constructor – it’s generally a really bad idea.
You can fix this particular problem by just not having instance variable initializers:
Now there will be no extra assignments between the superclass constructor completing and the subclass constructor executing. However, it’s not really a nice solution – it would be better to redesign it to avoid calling the overridden method in the superclass constructor.
I’d also try to get rid of the public fields, too… make them private, to avoid exposing the implementation details of your class.
See section 12.5 of the JLS for details about how constructor execution occurs.