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

  • 25
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值