谈谈Java/Kotlin中接口回调

在谈接口回调之前,想什么是接口?在学习类的时候,我们就得知接口主要是用来把某个功能抽象起来,之后,不同的类实现此功能,但其实现的功能不同。

一个生动的例子,把动物的叫这一行为抽象为一个接口,之后不同动物由不同的类代替,这些动物类都实现了这个“叫”接口,但是,他们实现不一样,因为每个动物的叫声都不一样

上面所述为接口的基本定义和功能,接口除了上面的功能外,还可以用来回传数据,也就是所谓的接口回调,即本文谈论的主题

接口回调应用情形

接口回调主要是将数据/状态回传给调用者,举个常见的例子,下载功能

我们定义一个下载的类,此类存在一个download方法,我们只要实例化此类,用对象的调用方式来调用download方法,即可开始下载

问题来了,我们想要得到下载完成这个状态,那么该如何实现呢?

大家可能想到的是一种较为简单的方法,使用返回值来判断当前是否完成,给download方法声明返回值,下载完毕之后返回true

上面的方法可行是可行,但是如果需要得到多个数据呢?如下载完成之后需要返回一个File对象,下载失败则是返回错误信息Exception,按照上面的逻辑的话,你得定义两个类,用来存储数据?然后根据不同的情况返回不同的对象?但是返回值的对象只能是一种类型,你两个类该怎么办?

于是呢,我们可以选择接口回调,可以比较方便的实现上述的问题。

class DownloadUtil { fun download(downloadListener: DownloadListener) { try { //下载操作... //一般下载操作肯定是有个File对象进行读写操作,这里我就省略了 downloadListener.success(file)
        } catch (e: IOException) {
            downloadListener.error(e)
        }
    } interface DownloadListener { fun success(file: File) fun error(e: Exception) }
} 

可以看到,DownloadListener有两个接口方法,success()和error(),当调用者调用的时候,传递了一个接口对象,之后在各自不同的方法就可以处理不同两种情况的逻辑了

val downloadUtil = DownloadUtil()
downloadUtil.download(object :DownloadUtil.DownloadListener{ override fun success(file: File) { //下载成功的相关操作 } override fun error(e: Exception) { //下载失败的相关操作 }

})

Kotlin优雅的接口回调

Kotlin与Java不同的是,如果某个接口有一个方法的话,可以使用Kotlin中的接口参数
这里就谈谈如何使用Kotlin优雅的实现一个接口多方法

上面下载的接口我们是定义了两个方法,一个是下载成功,另外是下载失败,在实现接口的时候,我们必须两个方法都实现,哪怕你不关心某个方法,你都要实现,但方法里面不写任何代码,如果接口方法多的话,简直是地狱

Kotlin的object关键字就是相当于Java中用new来实现接口方法

那么有没有可以自由选择实现某个接口方法的办法呢?当然有,那就是Kotlin中提供的DSL语法

我们把上面的用Kotlin优雅的重构一遍

1.接口构造类

我们需要把接口改造成接口的构造类,如下代码所示

inner class ListenerBuilder {
    internal var successListener: ((file: File) -> Unit)? = null internal var errorListener: ((e: Exception) -> Unit)? = null //这里的方法名之后需要调用 fun onSuccess(action: (file: File) -> Unit) {
        successListener = action
    }

    fun onError(action: (e: Exception) -> Unit) {
        errorListener = action
    }
}

对比: interface DownloadListener {
    fun success(file: File)
    fun error(e: Exception)
}

fun success(file: File) 改造为接口参数((file: File) -> Unit),如果有返回值,把Unit改成对应返回值类型即可

2.提供方法传递接口构造类

private lateinit var mListener: ListenerBuilder

fun download(listener: ListenerBuilder.() -> Unit) {
    mListener = ListenerBuilder().also(listener) try { //下载操作... if (::mListener.isInitialized) {
            mListener.successListener?.invoke(File(""))
        }
    } catch (e: IOException) { if (::mListener.isInitialized) {
            mListener.errorListener?.invoke(e)
        }
    }
}

PS:这里你也可以选择声明另外的方法用于单独设置接口,之后调用逻辑就可以不需要传递接口参数过来,这个看你喜欢吧

3.调用

val downloadUtil = DownloadUtil()
    downloadUtil.download{ //这里onSuccess和onError可选,IDE不会报错 onSuccess { 

        }
        onError { 

        }
    }

下载类源码

class DownloadUtil { private lateinit var mListener: ListenerBuilder

    fun registerListener(listener: ListenerBuilder.() -> Unit) {
        mListener = ListenerBuilder().also(listener)
    }
    fun download(listener: ListenerBuilder.() -> Unit) {
        mListener = ListenerBuilder().also(listener) try { //下载操作... if (::mListener.isInitialized) {
                mListener.successListener?.invoke(File(""))
            }
        } catch (e: IOException) { if (::mListener.isInitialized) {
                mListener.errorListener?.invoke(e)
            }
        }
    }

    inner class ListenerBuilder {
        internal var successListener: ((file: File) -> Unit)? = null internal var errorListener: ((e: Exception) -> Unit)? = null //这里的方法名之后需要调用 fun onSuccess(action: (file: File) -> Unit) {
            successListener = action
        }

        fun onError(action: (e: Exception) -> Unit) {
            errorListener = action
        }
    }

}
#Java##程序员#
全部评论

相关推荐

已经入职字节快一个月了,突然想起来之前那段时间的面经没有发,先发一下timeline吧。Tiktok 内容安全平台(人才库电话捞我):电话10.28 -> 一面10.30(我觉得你跟我们组业务挺match的,然后过了三天问hr挂了,应该是别人流程更快)阿里淘天:投递11.11->约面11.12->一面11.14(问得很简单,30分钟,手撕八股全过无后续)Kpi面腾讯wxg 微信小程序:投递11.13 ->约面11.14-> 一面11.17 (究极无敌拷打,问我多模态大模型涉及的算法?但是人很好)->11.19流程终止小红书 风控平台:投递11.16 —约面11.17  ->一面11.18 (抽象的面试官,面试感觉一般,问得前端网页安全相关的,确实没准备)->11.20挂百度 百家号:投递11.14 —>约面11.14 ->一面11.14(当场约2面)->二面11.24->口头告知offer, 拒绝(原因是业务不太好)美团 技术平台投递11.17 -> 约面(忘记了,没多久) ->一面11.19 ->二面11.21 (字节offer不想面了)快手 电商业务投递11.17 -> 约面11.18 ->一面11.19 -> 二面11.21(拒了)腾讯wxg 微信支付(被捞):(直接发面试邮件)技术一面12.05 ->技术二面12.11 ->技术三面12.17 -> hr面已拒绝(了解业务后拒绝,但是有转正hc,感觉还蛮可惜)字节跳动 xxxx:东家就不放具体的时间线了,大概是面完第二天就能知道结果,除了有几天ld请假了没填面评。不去wxg还有个原因是还在期末周,深圳学校来回太麻烦了,至少现在在的组感觉能学到很多的东西,自己的选择应该也没错。还是感概一下,一年前大二的时候投简历海投基本上石沉大海,无论大小厂约面比例很少。现在基本上投了就有面试,还都是以前梦寐以求的大厂,现在自己也有了更多的选择,也没有投太多简历。也感谢上一段实习的经历,很有意思的项目,无论是字节,腾讯,还是美团基本都有聊这个项目。面经需要等一下,也许等周末有空了再发给各位uu,感兴趣可以关注一下~有想要交流学习的同学也可以私信我,目前人在北京大钟寺~,可以找搭子~
正能量的牛可乐:这么多大厂面试下来,不仅摸清了不同公司的面试风格,还能精准避雷业务不匹配的岗位,血赚
实习简历求拷打
点赞 评论 收藏
分享
2025-12-12 19:01
南京航空航天大学 C++
秋招没咋投,准备 wxg 转正之后摆烂了。结果不堪字节 HR 的骚扰还是面了一下字节。之前想去字节的时候怎么面都挂。现在想着随便面一下结果三面技术面都意外顺利还有加面。十月中旬字节发了意向,wxg 转正结果无响应。十月底字节拉了保温群,wxg 口头通过,系统显示考核中。十一月初和字节 ld 交流之后得知 base 居然能选海外,甚至能小 wlb 一下,wxg 无响应无人联系。十一月中旬把字节 base 转到了海外,wxg 流程灰了,一问超时忘处理了,过两天又变考核中了。十一月下旬字节换了海外 HR 对接,问了期望薪资,wxg 考核终于显示通过,无 HR 保温,无其他保温。十一月底给字节报了个天价,想吓吓他们,同时告诉微信字节要开了,微信无响应。同样十一月底字节 HR 告诉我确实给不到那么高,但是能拿期权补上,问能不能接受。微信无响应。同样十一月底字节 HR 告知了具体方案,符合预期。 微信无响应。十二月上旬催 wxg 不开我就盲拒了,wxg HR 火急火燎的打电话问情况,问期望。我给了一个不算夸张的总包数字,因为今年市场在涨,过了三天还不联系我,我再催,约时间下午打电话,非得在我给出的数字上压下去几万,微信又不差这点,为什么不能满足我,让我没有拒绝的理由呢?一番纠结抗争,求稳还是追求挑战,最终选择接受迎接新的挑战,因为堂吉诃德永远不会停下脚步!回想起来,在 wxg 谈薪的阶段,我认为并没有给予我一定的重视,即使 HR 表示我在实习期间的表现和之前的面评都很靠前。也没有感觉到想要争取我,虽然我表示拒了 offer 之后要给我加面委定 t6 再涨,但我三个月没面试让我面面委那就是白给,还是算了。有缘再见了我亲爱的 wxg,再见了曾经的梦中情厂,再见亲爱的 mt,再见亲爱的朋友们。也再见,北京的一切。我想润了。秋招结束,卸载牛客,下一个三年,下一个五年,下一个十年后再来看看。
面试中的大熊猫爱吃薯...:我嫉妒得狗眼通红
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务