Java学习4-7_回调函数

回调函数

一.定义

回调函数就是一个通过函数指针调用的函数。如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

在这里插入图片描述

二.步骤:

  1. Aa() 方法调用类Bb() 方法
  2. Bb() 方法执行完毕主动调用类Acallback方法

在 Java中不存在函数指针,通常通过接口来实现:把实现某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。

三.例子(使用接口实现回调,传递对象也可以)

大概是个模拟快递柜取件运行的网络编程代码,在进行改造的时候遇到socket通信问题没有解决,就把代码做删减再贴出来了

1. 回调接口
/**
 * 回调接口
 * @author ShiYu
 *
 */
public interface CallBackInterface {
	void call();
}
2.使用回调,就用一个类来实现这个回调接口,重写call()方法,也就是最后实现回调的函数(上图中的B类)
/**
 * 实现接口,在这个类的方法中去调用另一个类的方法
 * Make a complaints by ShiYu:本来用Runnable接口也挺香的,非要整点炫酷的给自己挖坑 0_o?
 * @author ShiYu
 */
public class ClientThreadCallBack implements CallBackInterface {
    //此处相当于
	ExpressServerCallback expressServerCallback = new ExpressServerCallback();
	private Socket socket;

	// 构造函数将合传入
	public ClientThreadCallBack(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void call() {
		// TODO Auto-generated method stub
		System.out.println("回调");

		new Thread(() -> {
			// 线程信息
			System.out.println("cilent<" + Thread.currentThread().getName() + ">");
			System.out.println("\"" + socket.toString() + "\"");
			System.out.println("socket Info client port:" + socket.getPort());
			try {
				while (true) {
					System.out.println("输入的取件码:");
					String keyPackageNumber = br.readLine();// 阻塞方法
					System.out.println(keyPackageNumber);

                      //调用另一个类的方法,socket是引用类型
					ExpressServerCallback.takeOut(socket, keyPackageNumber);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}).start();
	}
}
3.在这个类(main)的方法中开启调用
/**
 * main方法,使用回调函数
 * @author ShiYu
 */
public class ExpressServerCallback {
	static ArrayList<Express> expressCabinet  = new ArrayList<>();
	public static void main(String[] args) {
		//从工具类获取server实例,单例模式(懒汉)
		ServerSocket serverSocket = SocketUtils.getInctence();
		try(serverSocket) {
			while (true) {
				Socket socket = serverSocket.accept();//阻塞方法
				//调用
				ClientThreadCallBack cliBack = new ClientThreadCallBack(socket);
				cliBack.call();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public synchronized static boolean takeOut(Socket socket, String keyPackageNumber) {
		//省略
	}
	
	/**
	 * 发送信息
	 * @param msg
	 * @return
	 */
	public static boolean sendMassage(Socket socket, String msg) {
		//省略
	}
}
4.说明

这个例子本意是在main方法中用回调的方法为多个用户开启通信的线程,然后如果客户管发送了数据,就回调main方法所在的类中对成员变量集合的增删查改,过程:

1.ExpressServerCallback.main -> cliBack.call()

ExpressServerCallback类中的main方法,实例化ClientThreadCallBack类的对象后,调用ClientThreadCallBack.call() 方法

2.ClientThreadCallBack.call() -> ExpressServerCallback.takeOut()

​ 在ClientThreadCallBack 类中的call方法中,经过一个阻塞方法(也可以是其他判断条件),当满足条件之后,回去调用了ExpressServerCallback中进行集合操作的方法

四.后记

本意是想实现多线程操作同一个集合的时候,避免将集合传过来传过去,然后想到这个好像很好玩的方法,结果socket的地方出现了bug,到现在还没有解决,socket不受控制的多发送了一次空数据,导致客户端和服务器的流程对接出现了问题

其实说到这个也就提到了 Vector

public synchronized E remove(int index) {
        modCount++;
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        E oldValue = elementData(index);

        int numMoved = elementCount - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--elementCount] = null; // Let gc do its work

        return oldValue;
    }

可以看到源码中用了synchronized 内置锁,当然,多线程想要保证线程安全就要牺牲效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值