1. 程式人生 > >Android開發基礎 -- 實體類 和 抽象類 詳解

Android開發基礎 -- 實體類 和 抽象類 詳解

1. 實體類


       在日常的Java專案開發中,entity(實體類)是必不可少的,它們一般都有很多的屬性,並有相應的setter和getter方法。entity(實體類)的作用一般是和資料表做對映。所以快速寫出規範的entity(實體類)是java開發中一項必不可少的技能。

       大概的說,實體類就是:屬性+get/set方法。

  在專案中寫實體類一般遵循下面的規範:

               1、

實體類的名字儘量和資料庫的表的名字對應相同。

    2、根據你的設計,定義一組你需要的私有屬性(如:private int age;)

    3、根據這些屬性,建立它們的settergetter方法。(AndroidStudio 等整合開發軟體可以自動生成。具體怎麼生成請自行百度。)

    4、提供有引數的構造器(所有的引數)和無引數的構造器(如果你不手動寫上構造方法。會預設幫你加上一個無參構造方法[不會顯示出來])

                         關於構造器可以看看這幾篇文章(在下面我也會大概說下):

構造器的作用是什麼?  Java構造器和方法的區別 

    5、重寫父類中的eauals()方法和hashcode()方法。(如果需要涉及到兩個物件之間的比較,這兩個功能很重要。)

                                  關於重寫這兩個方法的原因可以看看這幾篇文章: 

重寫equals和 hashCode方法 為什麼重寫equals的同時必須重寫 hashcode為什麼要重寫equals

                                                                                                                            如何重寫hashCode()和equals()方法1 如何重寫equals和 hashCode方法2

    6、實體類應該實現Serializable介面(序列化)。(如:public class BaseEntity implements Serializable { }    )

                                   實體類為什麼要序列化請參考這篇文章和這個貼: java實體類實現序列化的意義 (詳細的解析) 和  Java序列化的意義(通俗易懂)

            7、還應該有個屬性serialVersionUID(序列化版本號)。  (版本號為自動生成的,方法看下面網址)

                                   關於serialVersionUID作用介紹請看兩篇文章: serialVersionUID作用   和 AndroidStudio自動生成SerialVersionUID方法
             

 下面是我寫的一個實體類(entity)例子:具體的細節都用註釋標註了。

/**一個學生的Java實體類*/
class Student implements Serializable{
    /**
     * 序列化版本號(自動生成,方法請看上面)
     */
    private static final long serialVersionUID = 88722423642445L;
    //定義的私有屬性
    private int id;
    private String name;
    private int age;
    private double score;
    //無引數的構造器(如果不寫系統會自動生成無引數的構造器,但不會顯示出來)
    public Student(){
        
    }
    //有引數的構造器
    public Student(int id,String name,int age, double score){
        this.id = id;
        this.name = name;
        this.age = age;
        this.score = score;
    }
    //建立的setter和getter方法
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
    //由於id對於學生這個類是唯一可以標識的,所以重寫了父類中的id的hashCode()和equals()方法。
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (id != other.id)
            return false;
        return true;
    }
    
}


ps:
A.  關於構造器作用
利用構造器引數初始化物件的屬性
  舉個例子:
public class Animal {
    private int legs;

    //無參構造器
    public Animal() {
        legs = 4; 
    }  
    //有參構造器
    public Animal(int legs) {
        this.legs = legs; 
    }    
    public void setLegs(int i) { legs = i; }
    public int getLegs(){return legs;}
}
建立Animal類的例項:Animal a=new Animal();   //呼叫無參構造器,將legs初始化為4;(即 a.legs=4)
                                         Animal a=new Animal(10);   //呼叫有參構造器,將legs初始化為10;(即 a.legs=10)

註釋:構造器的名稱必須與類名相同。修飾符:public、private、protected
構造器不是方法,沒有返回值(連void也不能寫)


B.  關於重寫equals() 和 hashCode()方法的大致原因(具體介紹可以看看上面給出的那幾個文章地址) :
默 認equals在比較兩個物件時,是看他們是否指向同一個地址的。
但有時,我們希望兩個物件只要是某些屬性相同就認為他們的quals為true。比如:
Student s1 = new Student(1,"name1");
Student s2 = new Student(1,"name1");
如果不重寫equals的話,他們是不相同的,所以我們要重些equals,判斷只要他們的id和名字相同equals就為true,在一些集合裡有時也這樣用,集合裡的contain也是用equals來比較;

另外:equals()相等的兩個物件,hashcode()一定相等; 
equals()不相等的兩個物件,卻並不能證明他們的hashcode()不相等。



實體類 總結: 實體是就是Java中的O/R Mapping對映,即資料庫中的一個表對映成對應的一個Java類,其中還有一個對映檔案。給定一個較複雜的實體關係(如一對一,一對多,多對多),應該熟練地寫出實體類!!






2. 抽象類


簡單的說,抽象類就是從一般類中抽取他們的共性封裝成的類所以抽象類的特點就像抽象的事物一樣不是現實的不能被例項化

比如動物是抽象類(父類);等就是動物的具體類(例項化),即子類。
【如,貓狗的共性:四條腿,兩隻耳朵 等】

下面是關於抽象類的特點介紹:
1、 用abstract關鍵字來修飾一個類時,這個類叫做 抽象類;用abstract來修飾一個方法時,該方法叫做 抽象方法。(抽象方法一定定義在抽象類中)
2、 抽象方法沒有方法主體,就是沒有大括號,直接在小括號後面加分號。(如:public abstract void sayHello();  就是抽象方法。)
3、抽象類中的方法要被使用,必須有子類覆寫所有的抽象方法後,建立子類物件呼叫。
4、含有抽象方法的類必須被宣告抽象類,抽象類必須被繼承,抽象方法必須被重寫。
5、抽象類不能被例項化 (即不能用new建立物件),因為沒有意義。
6、抽象方法只需宣告,而不需實現。
7、 抽象類就是為了讓子類繼承的,它表示從一些具體類中抽象出來的型別。如果想要繼承抽象類的話,必須要在子類中覆寫抽象類中的全部抽象方法才行。
8、抽象類裡面的方法只需宣告,無需寫方法體,方法體在子類中覆寫時寫入方法體就行了。
9、如果子類只覆蓋了部分抽象方法,那麼該子類還是一個抽象類;抽象類中即可有抽象方法也可以有非抽象方法。
10、抽象類中可以不定義抽象方法,這種作用僅僅用於不讓該類建立物件。


下面是一個簡單的抽象類例子:
/**
 * 宣告抽象類;
 * 
 * (父類)
 **/
abstract class Animal{                   
    private String name;
    public Animal(String name){
        this.name = name;
    }

    public abstract void enjoy();        //宣告抽象方法


}


/**
 * 繼承抽象類;
 * 
 **/
class Dog extends Animal{

    private String forlorColor;
    public Dog(String name,String forlorColor){
        super(name);
        this.forlorColor = forlorColor;
    }

    // 實現抽象類裡面的抽象方法       (即加些功能)
    protected void enjoy(){
        System.out.println("dog叫聲~~~");
    }

}

注意:抽象類的繼承者必須實現抽象方法,否則也必須被定義成抽象的,由下一個繼承者實現。抽象類不能例項化物件。

又如,在Android開發中,經常會碰到自定義的 BaseActivity  、BaseFragment 等,這些就是大多數是抽象類;
我們在做Android應用的時候最基本的類當然是Activity了,我們一般的情況下要建立一個基類Activity然後讓別的Activity來繼承於它,但是我們可以使用一些小技巧來簡便我們對這個BaseActivity的使用,如下:
/**
 *  繼承activity的抽象類
 */
public abstract class BaseActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //子類繼承該抽象類BaseActivity後就會按著這些抽象方法一步一步執行
        
        findViews();    //先 繫結控制元件
        init();       //然後 初始化檢視
        setListeners();    //最後 設定監聽器
    }
    
    //宣告抽象方法
                         
    protected abstract void findViews();         
   
    protected abstract void init();           
   
    protected abstract void setListeners();    
}

那麼我們來看下實現該抽象類:
/**
 * 繼承抽象類,實現裡面的抽象方法
 */
public class MainActivity extends BaseActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

// 實現下面 抽象類裡面的抽象方法       (即加些功能等)

    @Override
    protected void findViews() {
    // TODO Auto-generated method stub
        //先在這裡繫結控制元件
    }
    @Override
    protected void init() {
    // TODO Auto-generated method stub
        //然後初始化檢視
    }
    @Override
    protected void setListeners() {
    // TODO Auto-generated method stub
        //最後 設定監聽器
    }
}

其實就是一個非常簡單的小知識點:
我們繼承於一個類,讓它成為抽象類,加上一些初始化的抽象方法這樣我們再繼承於這個類的時候就必須去實現這些抽象方法就不用我們去手動新增,這樣也不會讓我們丟失了一些操作,如初始化等,而且我們還把這些初始化的方法新增到了onCreate()方法中
這樣我們的子類只要繼承於BaseActivity,有以下兩點好處:
(1)肯定我們不用再去託運新增實現findViews()init()setLinsteners()這些初始化方法了,只需在這些子類中實行這些抽象方法即可;
(2)我們不用再在每個Activity中手動呼叫這三個方法,因為我們的BaseActivity已經為我們做好了封裝;

OK,以後我們就這樣搭建我們的BaseActivity吧;


*******************************************************************

網上有很多介紹BaseActivity的博文,多數是從應用的角度去描述的。

這裡,我所介紹的BaseActivity不同,主要從框架搭建的角度去介紹BaseActivity的使用

先看程式碼:

/**
 * 應用程式Activity的基類
 */
public abstract class BaseActivity extends Activity implements
        OnClickListener {

    private static final int ACTIVITY_RESUME = 0;
    private static final int ACTIVITY_STOP = 1;
    private static final int ACTIVITY_PAUSE = 2;
    private static final int ACTIVITY_DESTROY = 3;

    public int activityState;

    // 是否允許全屏
    private boolean mAllowFullScreen = true;

    //宣告抽象方法
    public abstract void initWidget();
    public abstract void widgetClick(View v);

    public void setAllowFullScreen(boolean allowFullScreen) {
        this.mAllowFullScreen = allowFullScreen;
    }

   @Override
    public void onClick(View v) {
        widgetClick(v);
    }

    /***************************************************************************
     * 
     * 列印Activity生命週期
     * 
     ***************************************************************************/

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        AppLog.debug(this.getClass() + "---------onCreat ");

        // 豎屏鎖定
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        if (mAllowFullScreen) {
            requestWindowFeature(Window.FEATURE_NO_TITLE); // 取消標題
        }

        AppManager.getAppManager().addActivity(this);

        initWidget();
    }

    @Override
    protected void onStart() {
        super.onStart();

        AppLog.state(this.getClass(), "---------onStart ");
    }

    @Override
    protected void onResume() {
        super.onResume();

        activityState = ACTIVITY_RESUME;
        AppLog.state(this.getClass(), "---------onResume ");
    }

    @Override
    protected void onStop() {
        super.onResume();
        activityState = ACTIVITY_STOP;
        AppLog.state(this.getClass(), "---------onStop ");
    }

    @Override
    protected void onPause() {
        super.onPause();

        activityState = ACTIVITY_PAUSE;
        AppLog.state(this.getClass(), "---------onPause ");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        AppLog.state(this.getClass(), "---------onRestart ");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        activityState = ACTIVITY_DESTROY;
        AppLog.state(this.getClass(), "---------onDestroy ");
        AppManager.getAppManager().finishActivity(this);
    }

}

定義一個初始化Activity控制元件的抽象方法initWidget();

像findviewbyid()這類程式碼就可以寫在這裡,不會影響程式碼結構了。這裡需要提一點的是:setContent()方法一定要寫在initWidget()裡,而不能再寫到oncreate裡面了,看程式碼可以知道,initwidget方法是存在於super()中的,而如果再寫到oncreate裡,就相當於先呼叫了findview再去呼叫setcontent,這樣肯定會報空指標異常。

關於豎屏鎖定,這個可以按需要新增,沒什麼說的。

還有一個要說的就是requestWindowFeature(Window.FEATURE_NO_TITLE); // 取消標題

對於這段程式碼,如果你要使用系統的ActionBar的時候,一點要記得呼叫setAllowFullScreen,設定為false,否則BaseActivity自動取消了ActionBar你又去使用,肯定也會出異常。

還有一點:Baseactivity已經實現了OnClickListener,所以子類無需再次實現,控制元件可以直接在initWidget裡面setonclicklistener(this);然後在widgetClick(View v)中設定監聽事件即可。

有關AppManager的內容我將放到下一篇《Android應用框架搭建》去講解,這裡大家可以先忽略。

有關生命週期的列印,我認為在除錯階段還是有必要的,畢竟看著每一個Activity的生命週期,如果出了問題馬上就可以清楚的知道是哪裡出了問題




其他關於BaseActivity的文章推薦:為你的Android應用定製屬於你的BaseActivity,  Android App框架設計之編寫基類BaseActivity