1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > java8 匿名内部类的前生今世

java8 匿名内部类的前生今世

时间:2023-12-23 10:38:47

相关推荐

java8 匿名内部类的前生今世

一 前言

本文会由浅入深,把匿名内部类的由来,定义,用法,以及在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 回调模式

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

举个栗子:

定义一个接口

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

定义含有成员方法为形参为接口类型的类

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()与匿名内部类的结合

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。