C转Java开发者对接口引用变量及相关代码逻辑的困惑
嘿,作为从C转Java的开发者,这种接口回调的写法确实容易让你摸不着头脑——毕竟咱们C里习惯用函数指针搞这类事,Java用了面向对象的接口来实现类似逻辑。我来一步步给你拆解清楚:
先把代码格式化看清楚
首先咱们把你贴的代码整理成规范格式,方便理解:
Main类代码
public class Main implements Impler.Clicker { public static void main(String[] args) { new Main(); } Main() { new Impler(this); } @Override public void toClick(int i) { System.out.print("clicked on " + i); } }
Impler类代码
public class Impler { private Clicker mClicker; Impler(Clicker clicker) { this.mClicker = clicker; mClicker.toClick(3); } public interface Clicker { void toClick(int i); } }
用C语言的思维类比理解
咱们把Java的概念对应到你熟悉的C语言逻辑上:
Impler里的Clicker接口 = C的函数指针类型定义
Java里的Clicker接口就相当于C里的这段代码:typedef void (*Clicker)(int);它定义了一个"行为规范":必须是一个接收
int参数、无返回值的方法/函数。Main类实现Clicker接口 = C里写符合函数指针类型的函数
Main类重写了toClick方法,就像你在C里写了一个符合Clicker函数指针类型的函数:void main_toClick(int i) { printf("clicked on %d", i); }而且因为Java是面向对象的,这个方法属于Main类的对象,所以咱们传递的是对象本身(而不是C里的函数地址)。
Impler的构造函数接收Clicker参数 = C里接收函数指针
当Main构造函数里调用new Impler(this)时,把当前Main对象(它符合Clicker接口规范)传给了Impler的构造函数,就像C里把main_toClick的地址传给某个函数:Impler_init(&impler, main_toClick);调用mClicker.toClick(3) = C里调用函数指针
Impler构造函数里的mClicker.toClick(3),本质就是执行传入的那个对象的toClick方法,对应C里的(*mClicker)(3),最终会执行Main类里的toClick方法,打印出clicked on 3。
完整运行流程梳理
咱们走一遍代码执行的顺序:
- 运行Main的main方法,创建一个Main对象;
- Main对象的构造函数触发,创建Impler对象,并把自己(
this)作为参数传给Impler; - Impler构造函数把传入的Main对象存到
mClicker变量里(因为Main实现了Clicker接口,所以可以赋值给Clicker类型变量); - 调用
mClicker.toClick(3),实际执行的是Main类里的toClick方法,输出结果。
本质:Java的回调模式
这段代码核心是回调模式——Impler类不需要关心具体是谁来处理"点击"逻辑,只要知道传入的对象符合Clicker接口的要求(有toClick方法)就行。这种模式在Java里到处都是,比如UI按钮的点击事件、异步任务的结果回调,都是这个思路。
内容的提问来源于stack exchange,提问作者elanonrigby

