2012-10-08 67 views
1

我正在構建一個Android應用程序,並且已經設置了一個基本的DBObject類來簡化表交互。 DBObject構造函數設置一個遊標並將其傳遞給虛擬方法loadRecord,該子類覆蓋此虛擬方法以加載其自己的屬性。根據loadRecord結尾處的Log.i調用,屬性都是正確的,但是一旦調用方法獲取對象,所有數據成員都會在類聲明中定義默認值,而不是加載的值(字符串爲空,浮點數是0.00等)。在子類的重寫方法中設置的Java類屬性丟失

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

這個構造函數調用重載loadRecord,它看起來像這樣在子類:那些在DBOBJECT構造函數中設置

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

成員仍然爲它們設置。我在這個完全損失....

在此先感謝!

回答

2

的問題是,你有實例變量初始化:

public String date = null; 
public String supplier = null; 
public String description = null; 
public float amount = 0.00f; 
public boolean receipt = false; 

的初始化將子類構造函數體執行之前執行父類的構造執行後,和。這是在構造函數中調用重寫方法的問題之一 - 通常這是一個非常糟糕的主意。

你可以只是沒有實例變量初始化解決這方面的問題:

public String date; 
public String supplier; 
public String description; 
public float amount; 
public boolean receipt; 

現在會有父類的構造完成,並在子類構造函數執行之間沒有額外的任務。然而,這不是一個真正的好的解決方案 - 最好重新設計它,以避免在超類構造函數中調用重寫的方法。

我也想盡量擺脫公共領域......讓它們變成私人的,以避免暴露你的類的實現細節。

有關構造函數如何執行的詳細信息,請參閱section 12.5 of the JLS

+0

謝謝。我意識到,公共數據成員是不屑一顧的,儘管我在Python中進行了比Java更多的編程,並且我試圖在Django的數據結構接口之後(隱約地)對它進行建模。我會把它清理乾淨。 我也想要超類調用的重寫方法使子類儘可能簡單;再次,我追求Django的不要重複自己的理想。如果子類總是要調用它自己的加載方法,那麼很多重複的代碼......:/ – Brad

+0

@Brad:當然,DRY是個好主意 - 但通常有其他方法,不需要調用覆蓋方法一個構造函數。如果可以的話,確實值得避免。至於「我會把它清理乾淨」 - 我強烈建議儘早做這件事;圍繞重構的良好意圖似乎沒有優先 - 最好是第一次正確編寫代碼。 –