Java接口與回調

1.接口的基本概念

1.1、interface是對類的一組需求的描述,但不給出需求的具體實現。
1.2、接口不是類,不能使用new來實例化一個接口,即不能構造接口的對象。但是我們其實經常可以與此命題相矛盾的代碼,實質上是匿名內部類。
1.3、儘管不能使用new實例化一個接口,但是可以聲明接口的變量。接口變量必須引用一個實現了接口的對象 才能發揮用處。
1.4、接口不能包含實例域或靜態方法,但是可以包含常量,且實現了該接口的類都會自動繼承這些常量,並且可以直接引用這些常量。(這種應用實際上偏離了接口概念的初衷,儘量少用)
1.5、接口的好處:一個類可以實現多個接口,這彌補了“java中一個類只能繼承一個父類”的侷限性。
1.6、接口的常見應用:①解決多重繼承問題; ②定義一個規範(協議); ③用於回調。

2.接口的簡單應用

應用1:解決多重繼承問題

Java語言本身是不支持類的多重繼承,但一個類卻可以實現多個接口。這樣,我們可以將一些抽象方法定義在接口中,間接地達到多重繼承的目的。例如:

public interface MyInterface1 {
    void fly();
}

public interface MyInterface2 {
    void walk();
}

public class Bird implements MyInterface1, MyInterface2 {
    private static final String TAG = "Bird";
    @Override
    public void fly() {
        Log.i(TAG, "I can fly");
    }

    @Override
    public void walk() {
        Log.i(TAG, "I can walk");
    }
}

應用2:定義一個規範(協議)

同一個接口可以有多個不同的實現類,但每一個實現類都必須重寫接口中所有的抽象方法。即接口不考慮這些實現類各自採用什麼方式實現這些功能,但它要求所有的實現類都必須有這些功能。

3.接口與回調

回調的基本實現方法,分爲三部分。
第一部分:定義接口A。
第二部分:定義了B類,B實現了A接口(必定也實現了接口規定的方法),將B的實例 作爲參數,傳入到C類實例中(通過C的構造函數傳入參數 或者 通過調用C類實例的方法傳入參數)。
第三部分:定義了C類,C類可以接收第二部分傳來的參數(構造函數的參數 或 某個方法的參數 的類型設定爲A),接收到這個參數後,就可以使用這個參數來調用B類中的方法(比如在適當的地方執行mOnClickListener.onClick(this))。
例1:這篇文章的“用於回調”部分 http://www.jianshu.com/p/cccb430a8ba0
例2:http://blog.csdn.net/xiaanming/article/details/8703708/
例3:Android中的OnClickListener的使用(例2文章中也提到了),這裏稍微分析下。OnClickListener即對應A,而B是implement了A的類(或者用匿名類),View(或其子類)對應C。View中通過setOnClickListener這個函數接收參數B,並保存在mOnClickListener中,在適當的地方執行mOnClickListener.onClick(this)便調用了B的onClick方法,並且將自己(this)傳遞給B,從而實現了回調。回調時帶回的參數(這裏是個view),可以告訴B 這是哪個view觸發了onClick(當然,如果每個button都用匿名內部類方式設置監聽,則view和監聽是一對一的關係)。

第一部分和第三部分寫法變化不大,第二部分有多種寫法,以OnClickListener爲例。
寫法1:採用內部類。MainActivity中創建了myListener這個類。

class myListener implements OnClickListener
{
    @Override
    public void onClick(View v) {
   //具體點擊操作的邏輯
   }
}
OnClickListener listener=new myListener();
button.setOnClickListener(listener);

寫法2:匿名內部類。

OnClickListener listener=new OnClickListener()
{
    @Override
    public void onClick(View v) {
   //具體點擊操作的邏輯
   }
}
button.setOnClickListener(listener);

注意 listener應該理解爲一個實現了OnClickListener接口的不知名的類的實例。

寫法3:匿名內部類精簡版

button.setOnClickListener(new OnClickListener()
{
    @Override
    public void onClick(View v) {
   //具體點擊操作的邏輯
   }
});

寫法4:lambda表達式版

button.setOnClickListener((view)->{//具體點擊操作的邏輯});

寫法5:MainActivity實現OnClickListener接口,然後將自己作爲參數傳入。

button.setOnClickListener(this)

當然,傳入的this是MainActivity的當前實例。(this關鍵字可以代表自身類的對象)(傳入的參數必然是個實例,不可能傳入“類”)

4.一些思考

4.1、android程序中,甚至只需要在佈局中設置android:onClick="onClick"而不需要像4.1那樣的代碼。查看View源碼可知,若設置onClick這個屬性,便會重新setOnClickListener。順便提一句,這篇文章總結了“按鈕設置監聽”的一些方式 http://www.jb51.net/article/108043.htm 當然任何view都可以設置監聽,其中Button的clickable默認爲true。
此外,從View源碼中可以看出, setOnClickListener中會再次將clickable設置爲true,因此若想設定clickable爲false,必須在setOnClickListener調用之後設定。
4.2、B和C的對應關係,以上許多例子爲1對1關係。
一對多:在MainActivity實現OnClickListener,並且有多個button時,可以通過回調帶回來的參數view識別。
多對一:比如一個button先後設置了幾個不同的OnClickListener,那麼應該以最後一個爲準。但是這裏的打電話的例子會不會出問題:
http://blog.csdn.net/xiaanming/article/details/8703708/,或者有沒有其他情況會出bug。
4.3、能否用抽象類或者超類之類的代替接口,實現回調。

5.參考資料

《Java核心技術》(第10版)
http://www.jianshu.com/p/cccb430a8ba0
http://blog.csdn.net/xiaanming/article/details/8703708/
http://www.jb51.net/article/108043.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章