java 匿名内部类

是什么?为什么使用匿名内部类?

参考:https://www.zhihu.com/question/49330534

 

一、是什么

(1)匿名内部类的特点

1.匿名内部类通常用来简化代码编写。

2.无法在别的地方(别的类中)使用匿名内部类。

3.使用匿名内部类有个前提条件:必须继承一个父类或实现一个接口。

(2)匿名内部类的实现

顾名思义,“匿名”指该类可以没有名称,“内部”指该类在某类内部创建。

我们在写线程的时候,一般会这么写:

Test.java

因为这条线程只使用一次,所以可以简化写法。

把线程类写成匿名内部类的形式:

这里的线程类没有名称,在Test类的内部,是典型的匿名内部类的实现。

不仅实现Runnable接口可以写一个线程类,继承Thread类也可以做到:

这也说明了实现匿名内部类的前提:匿名内部类必须实现接口/继承父类。否则将无法写成匿名内部类的形式。

既然是内部类,所以我们无法在别的地方(别的类中)使用这个类(名字都不知道怎么使用…),比如实例化,调用静态方法。

二、为什么使用匿名类

(1)简化代码

刚才我们提到:“匿名内部类通常用来简化代码编写”。那么到底简化了什么?

我个人认为,简化的就是我们平时接口-实现类的模式。在一般情况下,我们会这样写:

Test.java

在这里,我们调用了work方法。如果这个方法只需要使用一次(注意是只使用一次,如果需要使用多次方法,就不应该这样做),那么仅仅为了使用一次方法去特意新建一个Chinese类,是不值得的。

所以可以将其改造成匿名内部类的形式,简化到极致:

这样改写不但能够实现同样的效果,代码量也是最少的。

(2)调用protected方法

现在,我想在我的类中调用testMethod类的protected方法,但是这两个类不在同一个包下,就会导致没办法调用。

testMethod.java

出于无奈,我只能让我的类继承testMethod类,才能调用其protected方法。

我只是想调用一个protected方法而已,却不得不继承一个父类,付出的代价实在是很大(把父类中不需要的成员全都继承了下来,在初始化时先要初始化父类,效率变低)。

这时候匿名类就派上用场了。我可以实现一个匿名类AnonymousMethod继承testMethod类,并且定义一个getMethod方法。

Test.java

在这个getMethod方法内使用super调用需要的protected方法,最后就可以通过getMethod实现间接调用。

三、实践

有如下场景:Xie去一家公司面试,面试官需要查看面试者的年龄是否>=20,工作经验年数是否>=2,如果是则开始面试。

如果使用传统方法解决这一问题,如下:

Test.java

如果我们换成匿名内部类的方式来解决问题,可以把算法部分单独抽出来:

这个例子写完之后我感觉很奇怪,完全体会不到使用匿名内部类的好处。直到后来我看到了这种别人的分析,才恍然大悟:

有的时候, 为了实现一个功能或者实例化一个对象, 需要实现一个接口, 但是接口应用的地方很多, 但是每个地方的实现都不尽相同, 而且需要实例化的地方就只有那么一两处。

这个时候, 如果为了使用这些方法, 每个地方都声明一个类来实现接口的话, 就会浪费很多空间, 还得费时编译。

匿名内部类可以在需要的地方使用接口, 可以在使用的同时实现, 这样不但节省了空间, 还可以使代码更加清晰明了(因为具体逻辑在需要使用的地方展示了出来)。

回到我的例子,可以发现:需要校验数据的地方只有一处check(xie),这个check方法没有更多的实现,不需要写成接口,所以不适合使用匿名内部类。

如果要特意把算法抽出来,可以写成一个方法:

到目前为止,我好像还没有遇到需要刻意使用匿名内部类的写法(这个例子也是这样)。

顺带一提,可以使用java8中的lambda来代替实现:

关于lambda,之后我会另写文章来讨论。

四、总结

具体情况具体分析,不需要刻意使用。受到函数式编程的影响,在java8中,匿名内部类似乎逐渐被lambda取代,但是使用起来应该差不多。

重要的不只是怎么做,更是为什么。

发表评论

电子邮件地址不会被公开。 必填项已用*标注