N個例子讓你徹底理解java接口回調

說到接口回調,對於初學者來說,理解是真的難啊,不過沒有關係,看完本篇文章,你馬上就能理解接口回調啦!

概念

爲了便於讓大家都能無痛理解到接口回調,我決定用N個白話概念來給大家講解,總有一種解說方式適合你:

解說1:A讓B去做一件耗時(不一定耗時)的操作,而且並不知道要花費多少時間,B做完了後,告訴A事情做完了,並且把結果給A。當然,B在做這件事的時候,A還可以做其他事情。

解說2:世間總有我們難以到達的地方,比如人的胃出了問題,把頭伸進去檢查一下,肯定是不方便的,所以要用胃鏡檢查一下,就是下圖這個玩意兒:
這裏寫圖片描述
(媽媽,我在技術博客上居然看到了胃鏡!)
然後我們直接將這個玩意兒伸進胃裏,我估計病人就要開罵了,“你特麼直接伸根管子進來要幹嘛!“,確實,直接伸根管子進來,我想醫生也不會做這種蠢事,然後醫生會把這跟管子連接到一個特殊的儀器上,再伸管子進來,不然醫生怎麼看病人胃裏啥情況,是吧?
如圖儀器:
這裏寫圖片描述
這個例子,我們再分析一下。管子伸進病人胃裏,管子得到圖像,並且將圖像返回到儀器上。老實說管子和儀器其實在接口回調的思維方向中,應該是一體的,接口就是那根管子,提供提供一個得到圖像的方法,儀器就是這個接口的具體實現,將接口得到的圖像,顯示到儀器上,醫生就可以直接通過儀器看到圖像了。

現在我們將這個例子,強行套上解說1中的A和B:儀器A讓管子B去得到圖像,儀器A也不知道管子B什麼時候可以得到圖像,當管子B得到圖像後,馬上返回給儀器A。當然,管子B在得到圖像的過程中,儀器A還可以做其他事情,比如屏幕角落顯示個時間啥的。

解說3: 假設我們有一根水管,通水後,一直在流水,如圖:

算了,還是動圖好看:

假設這是一個水管的截面圖,水緩慢的從水管中流過,然後這個水管中有一些其他東西,就叫東西A吧,然後現在的水管是這個樣子的:

接下來,大家打算把這個東西A給拿出來,於是製作了一個專門能抓取A的抓取器B,在水管中間掏了一個孔,然後把B放了進來,先總結下:A是東西,B是抓取器,然後現在就是這樣的
其中紅色是B:

然後現在東西A也被抓到了,那麼就可以使用A了,由於B是一個抓取器,很多設備都可以和B直接連接,然後得到A,所以:

儀器1

儀器2

所以有很多儀器都能夠連接到B,至於這些儀器拿到A幹嘛,這就看每個儀器內部是怎麼處理的了。

故事講完了,接下來我要強行套用接口回調的事情了,首先在這個故事裏面,我們出現了一個4種東西:

  1. 水中的A
  2. 專門獲取A的B
  3. 可以和B連接的各種儀器

先說說接口回調的概念,白話文版本:接口回調就是,我們需要一個東西,而這個東西我們的儀器不能直接拿到,於是我們決定製作一個小器具深入其中,然後讓那個小器具去得到我們需要的東西,這個小器具可以直接連接到我們的儀器,然後通過這個小器具把東西傳給儀器。

我再把這句話稍微的加些專業詞彙:接口回調就是,我們需要某些數據,但這些數據不能直接拿到,於是我們創建一個接口去幫我們拿,但接口畢竟是個接口,他啥也不能幹,只能得到數據,所以我們需要這個接口的具體實現類,也就是上面白話文中的儀器。然後具體的實現類再來對數據進行處理。

大家看到上面這個概念,可能會有以下疑問:

  1. 啥數據啊,我還不能直接拿到?
  2. 爲啥接口就可以拿到這些數據
  3. 啥叫接口啥也不能幹啊,不能幹爲什麼我們要用接口

問題1: 啥數據啊,我還不能直接拿到?
比如,我們寫了如下代碼,執行了一個data方法,是不是感覺這個data()方法毫無意義,假設這是平時開發中的某一個方法。

public class Main {

    public static void main(String[] args) {
        data();
    }


    private static void data() {
        int a = 100;
        int b = 200;
        int c = 300;
        int d = 400;
    }

}

現在有一個data方法,我們想得到data方法裏面的 變量b 的數據,
(先別吐槽這些代碼很蠢,在開發中經常會遇到這些情況的,要得到某個地方的數據,直接拿又不方便,那個地方的數據多如牛毛,而我只取某些數據。)

問題2: 爲啥接口就可以拿到這些數據
看着啊,接口怎麼拿到這些數據的。

public class Main {

    // 接口
    interface Callback {
        void getData(int x);
    }

    static Callback callback;

    public static void main(String[] args) {
        data();
    }


    private static void data() {
        int a = 100;
        int b = 200;
        if (callback != null) {
            callback.getData(b);
        }
        int c = 300;
        int d = 400;
    }

}

別跳,老老實實看代碼,不難理解的。

看完之後一臉懵逼,大哥,這個接口有啥用,寫在這裏毫無意義啊。
我說你先別急,這時候拋出第三個問題:
問題3. 啥叫接口啥也不能幹啊,不能幹爲什麼我們要用接口
看到上面的代碼,發現接口並沒有任何卵用,爲什麼沒卵用,因爲這個接口啥也不是啊,就真的是個接口,沒有被實現吧,沒有被實現,怎麼可能有用,那我們來實現下。

callback = new Callback() {
            @Override
            public void getData(int x) {
                System.out.println(x);
            }
        };

匿名類實現方式,嗯,講究,這個時候整個代碼的感覺就是這樣的。

public class Main {

    // 接口
    interface Callback {
        void getData(int x);
    }

    static Callback callback;

    public static void main(String[] args) {

        callback = new Callback() {
            @Override
            public void getData(int x) {
                System.out.println(x);
            }
        };

        data();

    }


    private static void data() {
        int a = 100;
        int b = 200;
        if (callback != null) {
            callback.getData(b);
        }
        int c = 300;
        int d = 400;
    }

}

這個時候,運行打印出來的數據就是200了,我們完成了接口回調。

其中之一的小用途

假設有一個耗時的操作:在網上下載一張圖片,我們並不知道下載這張圖片具體要花費多少時間,於是我們開一個線程去下載圖片,當該線程下載完圖片後,把圖片給需要的人。

用法

既然是接口回調,那就少不了接口啦:

public interface CallBack {
	void callBack(String picture);
}

這裏我們定義了一個接口,並且設置了一個方法,方法裏的參數就是B執行完後返回給A的結果。

那麼這個接口該怎麼用呢?

這裏我們假設一個場景:A需要在網上下載一張圖片,但是A並不知道下載這張圖片需要多少時間,於是A開了一個線程B去下載這張圖片,並且B下載完後將圖片給A。

這個B線程我們應該怎麼寫?

public class MyThread extends Thread{

	private CallBack callBack;

	public MyThread(CallBack callBack) {
		this.callBack = callBack;
	}

	@Override
	public void run() {
		super.run();
		
		// 模仿耗時操作
		for (int i = 0; i < 10; i++) {
			try {
				Thread.sleep(500);
				System.out.println("圖片下載中。。。(假裝耗時)");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		callBack.callBack("得的圖片!!!");
		
	}
	
}

接下來我來解釋下怎麼理解這個線程中的接口。
我們在線程中聲明瞭一個接口,主要是爲了在耗時操作完成後,使用這個接口中的那個callBack(String picture)方法。將結果丟到這個方法的參數中。

但是臥槽!這不就是一個接口嗎,方法體在哪裏,就算把結果傳給了這個方法裏面又有什麼卵用??
我的結果呢?哪去了!!!

帶着這些疑問,我們開始使用這個構造方法含有接口的線程。

使用:

	MyThread myThread = new MyThread(new CallBack() {
			
			@Override
			public void callBack(String picture) {
				System.out.println(picture);
			}
		});
		
	myThread.start();

我們發現在使用這個線程的時候,需要在構造方法中傳遞一個已經實現了該接口的類,匿名類走起。
然後會在這個匿名類中生成一個方法,原來方法體在這裏,我們發現這個方法還有可以利用的參數,沒錯!這個參數就是經過耗時操作返回給我們的結果,也就是那張圖片!!
趕快運行一波!!!

運行結果:

圖片下載中。。。(假裝耗時)
圖片下載中。。。(假裝耗時)
圖片下載中。。。(假裝耗時)
圖片下載中。。。(假裝耗時)
圖片下載中。。。(假裝耗時)
圖片下載中。。。(假裝耗時)
圖片下載中。。。(假裝耗時)
圖片下載中。。。(假裝耗時)
圖片下載中。。。(假裝耗時)
圖片下載中。。。(假裝耗時)
得的圖片!!!

這麼簡單易懂的代碼真是騷的飛起!

這就是我對接口回調的理解及使用方法,希望你們看了這篇後再也不會爲接口回調而煩惱!

源碼下載:http://download.csdn.net/detail/it_xf/9790588

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