一 前言

本文会由浅入深,把匿名内部类的由来,定义,用法,以及在java5,和java8中一些新的语法,对其形式上的变形,阐述的清清楚楚。对于完全没有接触过匿名内部类的朋友,或者对其一知半解的朋友,相信读完此文,会豁然开朗。

二 相关概念

对于匿名内部类,首先应该明白一些相关基本概念。顾名思义,他是一个类,并且是内部的类,还是一个匿名的类。

2.1内部类

2.1.1什么是内部类

  • 当一个类的定义中出现另外一个类的类体中时,那么这个类就叫内部类(inner),而这个内部类所在的类就叫外部类(outer)。比如类A中又存在另外一个类B,那么我们就可以把类B叫做类A的内部类。
  • 所以类的内容就会比我们常见的成员变量,成员方法,构造方法等等 多了一个新的东西叫内部类。

**定义:**当一个类的存在只是单单为另外某一个类服务时,那么就可以把这个类定义为 为其服务的类中的一部分—内部类。

2.1.2 内部类的作用

对于常规的类,内部类可以隐藏该类的实现细节并且可以方便访问外部类的私有成员,而不需要再提供公有的get 和set方法。

2.1.3 内部类的分类

所谓其分类,只是把内部类放在相对外部类的位置在哪儿,其放的位置不同,名字就会不同,对应的功能也会不同,最常见的还是匿名内部类。

  • 普通内部类:直接讲一个类的定义放在另外一个类的类体中
  • 静态内部类:使用static关键字修饰的内部类,隶属于类层级
  • 局部内部类:直接讲一个类的定义放在方法体的内部
  • 匿名内部类:指这个内部类没有名字。

总结
通俗的讲:比如类A中又存在另外一个类B,那么我们就可以把类B叫做类A的内部类。匿名内部类是内部类的一种,但是这个类没有类名,是匿名的。我们这样做的用法是,作用是忽略其这个内部类的实现细节,并且是一次性的。对于以上概念性的阐述,

2.2 回调模式

定义: 如果一个方法的参数是接口类型,则在调用此方法时,需要传递一个实现此接口类型的对象;同时该方法在运行时,会调用传递参数对象的方法(对象在接口中定义)
举个栗子:

  1. 定义一个接口
public interface AnonymousInterface {// 自定义抽象方法public abstract void show();
}
  1. 定义含有成员方法为形参为接口类型的类
public class AnonymousInterfaceTest {// 假设已有下面的方法,请问如何调用下面的方法?public static void test(AnonymousInterface ai) {ai.show();}public static void main(String[] args) {// Error:接口不能实例化//AnonymousInterfaceTest.test(new AnonymousInterface());
}

我想给test()方法传参,但是形参是一个接口,不能通过new AnonymousInterface()对其进行传参。如果要对其传参,那么必须new 一个实现这个接口的类,将new出来的对象传入该方法。
3. 实现AnonymousInterface 接口的类

// 实现上面接口的类
public class AnonymousInterfaceImpl implements AnonymousInterface {@Overridepublic void show() {System.out.println("这里是接口的实现类!");}
}

这样就可以传参;并且实现了java最重要之一 多态。可以很明显的看出,只要我传入的实现接口AnonymousInterface的类中重写的方法逻辑不同,最终代码运行的结果也会不同。即通过形参类型是接口,传入的形参是实现改接口并new 的对象。
一下代码运行的结果是:

这里是接口实现的类型。
public class AnonymousInterfaceTest {// 接口类型的引用指向实现类型的对象,形成了多态public static void test(AnonymousInterface ai) {// 编译阶段调用父类版本,运行调用实现类重写的版本ai.show();}public static void main(String[] args) {AnonymousInterface ai = new AnonymousInterfaceImpl();AnonymousInterfaceTest.test(ai);}
}

上面的代码可以进一步简化。在传参的时候再创建对象。
这样就完全实现了回调模式。即方法test()的形参是一个接口AnonymousInterface,在调用该方法时,在传参的时候new 一个实现改接口的对象new AnonymousInterfaceImpl(),那么在最终的运行时,实现的逻辑是AnonymousInterfaceImpl()中的System.out.println("这里是接口的实现类!");

public class AnonymousInterfaceTest {// 接口类型的引用指向实现类型的对象,形成了多态public static void test(AnonymousInterface ai) {// 编译阶段调用父类版本,运行调用实现类重写的版本ai.show();}public static void main(String[] args) {AnonymousInterfaceTest.test(new AnonymousInterfaceImpl());}
}

2.3 匿名内部类

通过上面的一个栗子,我们明白了是什么是回调模式,并且其实现了java多态的方式之一。
上面的例子中使用的类型是接口类型,实际上还可以是类类型,在传参的时候可以是类的子类。

接口/类类型的引用作为方法的形参时,实参的传递方式有两种,其中一种就是以上栗子中呈现:自定义类实现改接口/继承类并重写里面的方法,然后创建该类的对象作为实参传递。但是为了传参,而单独实现一个接口的类。

  • 一方面在运行的时候会将接口实现类加载到方法区中,占用内存空间;
  • 另外还不够简化,我们希望在传参的时候再实现该接口,并new该类。

(终于引入今天的主题了)另外一个种就是使用匿名内部类,其语法格式为:

接口/父类类的 引用变量名 = new 接口/父类类型(){方法重写}
与我们常用的 new 只能是一个对象不同,这里还可以new 一个接口,初次接触,可能在语法上会有点难以理解,不是接口不能 实例化对象吗?
针对上面的栗子,还是同一个接口

public interface AnonymousInterface {// 自定义抽象方法public abstract void show();
}

对于其调用,不需要接口的实现类,就可以变成如下代码。

public class AnonymousInterfaceTest {public static void test(AnonymousInterface ai) {ai.show();}public static void main(String[] args) {// 使用匿名内部类的语法格式来得到接口类型的引用,// 格式为:接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };AnonymousInterface ait = new AnonymousInterface() //public class AnonymousInterfaceImpl implements AnonymousInterface//{@Overridepublic void show() {System.out.println("匿名内部类就是这么玩的,虽然你很抽象!");}};  //  注意需要分号结尾AnonymousInterfaceTest.test(ait);}
}

注意我在代码中的public class AnonymousInterfaceImpl implements AnonymousInterface如果加上这段,在语法上肯定是错误的,但是其实这里就是实现接口的这么一个类,并且实例化这个类。只是我们需要这个类是匿名的,不关心它的名字,于是就变成上面代码去掉public class AnonymousInterfaceImpl implements AnonymousInterface成为一个真正的匿名内部类。

上诉代码可以做一个小小的简化,把创建匿名内部类放在了形参中创建并传递。这就是我们平常匿名内部类常见的表现形式,即如下:

public class AnonymousInterfaceTest {public static void test(AnonymousInterface ai) {ai.show();}public static void main(String[] args) {AnonymousInterfaceTest.test(new AnonymousInterface() {@Overridepublic void show() {System.out.println("匿名内部类就是这么玩的,虽然你很抽象!");}});}
}

其优点相对于上面而言,就是这个匿名内部类在使用是才会去创建,并实例化,当使用完成后,这个类和这个类创建处理的对象也一同销毁了,节约了内存资源。但是其缺点就是语法上有些隐晦难懂,对于初学者不太友好。

2.4 lamda表达式与匿名内部类

2.4.1 什么是lamda表达式

在java8 之后,出现了lamda表达式,其实这种语法形式在其他语言中也经常见到,比如python、 JavaScript,不过倡导代码直接明了的python不提倡使用这种语法。lamda表达式目的也是为了减少代码量,但是会略隐晦一些,不是直接明了的表达代码的意思。在java中还是会大量使用,毕竟java隐晦难懂的语法多着去了(猛男落泪ing )。

lamda表达式可以简化上述代码,格式为:(参数列表) -> {方法体}
可以看到就是继续省略掉 new AnonymousInterface() 和方法名,只留下业务逻辑最核心的部分,方法体内部逻辑代码。
lamda表达式如果有不懂的,可以百度一下 ,这里就不深入讲解,其实还是蛮简单的。继续上面那个例子。

public class AnonymousInterfaceTest {public static void test(AnonymousInterface ai) {ai.show();}public static void main(String[] args) {AnonymousInterface ait = () -->{System.out.println("匿名内部类就是这么玩的,虽然你很抽象!");}AnonymousInterfaceTest.test(ait);}
}

同样上诉继续简化就变成:

public class AnonymousInterfaceTest {public static void test(AnonymousInterface ai) {ai.show();}public static void main(String[] args) {AnonymousInterfaceTest.test(() -->{System.out.println("匿名内部类就是这么玩的,虽然你很抽象!"));}
}

同样一段逻辑,根据不断的简化,加入匿名内部类,lamda 最终代码量减少很多,这样在开发过程中,也会提高效率。

匿名内部类在java中是一种很常见的类型,本来之前也是一知半解,此文也是自己知识点的一个总结,如果有任何问题,欢迎大家指出。

2.5集合迭代器 forEach()与匿名内部类的结合

------------后面再续更-------------------------

java8 匿名内部类的前生今世相关推荐

  1. java的前生今世_HBaseGC的前生今世-身世篇

    网易视频云是网易倾力打造的一款基于云计算的分布式多媒体处理集群和专业音视频技术,提供稳定流畅.低时延.高并发的视频直播.录制.存储.转码及点播等音视频的PAAS服务,在线教育.远程医疗.娱乐秀 网易视 ...

  2. nio java是什么_Java NIO 的前生今世 之一 简介

    简介 Java NIO 是由 Java 1.4 引进的异步 IO. Java NIO 由以下几个核心部分组成: Channel Buffer Selector NIO 和 IO 的对比 IO 和 NI ...

  3. DevOps Master课程总结:知否知否,应是DevOps肥ITIL瘦(送ITIL4前生今世)

    作者:北京老李:DevOps布道师.IT管理咨询师.EXIN授权EXIN DevOps Master(大师级)讲师(首批全国十名).首批ITIL Expert讲师.EXIN授权EXIN Agile / ...

  4. 立委科普:问答系统的前生今世

    立委科普:问答系统的前生今世 以下全文转载自李维老师的博文:立委科普:问答系统的前生今世. 上周信笔涂鸦写了个不伦不类的科普([立委科普:从产业角度说说NLP这个行当]),写完自我感觉尚可,于是毛遂自 ...

  5. 高并发网站架构与正态分布的前生今世

    高并发网站架构 什么是服务器? 不就是提供"付费"."免费"服务的高档电脑嘛! 你提到服务? 存储一个图片,读取一篇文字,观看一个动作片,计算一个账户存款,- ...

  6. 国产手风琴的前生今世

    国产手风琴的前生今世 国产手风琴品牌的前世今生 "鹦鹉"商标纠纷案 上海百乐和天津鹦鹉的恩怨情仇 国产手风琴的境遇 前些日子朋友建议我学习手风琴,网上查了一下资料,了解了一些国产手 ...

  7. Win Server 08 R2前生今世

    在刚刚结束的微软TechEd 2009大会上,微软面向企业级市场推出了七种武器:Windows 7.Windows Server 2008 R2.Exchange Server 2010.Forefr ...

  8. 网易视频云:HBase GC的前生今世 – 演进篇

    现在,网易视频云与大家分享一下HBase GC的前生今世–演进篇. 最原始的HBase CMS GC相当严重,经常会因为碎片过多导致Promotion Failure,严重影响业务的读写请求.幸运的是 ...

  9. 价格不断飙升的 GPU,居然「出生」这么晚!一文带你了解 GPU 的前生今世

    \ 转自 | 新智元 来源 | vice 编辑 | keyu GPU真正的出现,其实并没有我们想象的那么早--大家了解GPU的真实历史吗?谁是GPU的开创者?谁又是历史的篡改者?GPU的当今的短缺到底 ...

  10. ARM与x86之2--Atom的前生今世

    http://blog.sina.com.cn/s/blog_6472c4cc0100kq8b.html 世间本没有PC处理器和嵌入式处理器.这两种处理器在同一天诞生. 1976年5月,Intel开始 ...

最新文章

  1. 计算机研究生上课时间自由吗,计算机在职研究生面授班主要的上课时间安排是怎样的呢...
  2. 使用nginx动静分离后,druid被拦截的解决方法
  3. linux下面破解rar压缩包密码
  4. Flask安装首页显示
  5. 在CKEditor中创建自己的命令按钮
  6. 华为哪款手表支持鸿蒙,华为Watch 3最早或于5月发布 采用鸿蒙系统并支持eSIM
  7. 数据分析的5层解读,报表仍是有效的落地实践!
  8. iOS底层:PAGEZERO的作用
  9. 数模笔记:蒙特卡洛模型
  10. 电子协会 C语言 1级 34 、分段函数
  11. CSS3弹性布局、响应式布局、PS
  12. 2021年总结:厚积薄发,突破自我
  13. 初探大规模GBDT训练
  14. 菜鸟Django--更改和删除
  15. 关于python赋值语句下列选项中描述正确的是_关于 Python 语句 P = –P,以下选项中描述正确的是________...
  16. [论文学习] - 2014ECCV - TCDCN
  17. ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost:3306‘ (10061)的解决方法。
  18. 【关于ChatGPT的30个问题】1、ChatGPT是什么?/ By 禅与计算机程序设计艺术
  19. MYSQL数据库备份全攻略
  20. 蓝桥杯 未名湖边的烦恼

热门文章

  1. Linked list
  2. LaTeX 1软件下载安装
  3. 30行Python代码 刷王者荣耀金币
  4. 查看计算机启动项命令,运行命令开机启动项msconfig命令简介及教程
  5. 无线路由器的AP、Client、WDS、WISP使用功能图解(清晰明了)
  6. 1987:【20CSPS提高组】括号树P5658 [CSP-S2019] 括号树
  7. Windows XP将显示桌面图标放到任务栏
  8. 省份和城市的级联下拉菜单
  9. 有测试狗狗好坏的软件吗,6个测试判断狗狗性格,胆小或凶猛一测便知,你家狗狗是哪种?...
  10. Spring Data -Specification用法和常用查询方法(in,join,equal等)