欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java 中引入内部类的意义?

程序员文章站 2022-04-25 20:25:23
前言 这是个好问题,因为它让我想起来自己刚学到内部类时候的“想用的冲动”。 导致我代码里到处都是层层的内部类套嵌。不但经常搞得静态域错误一堆(内部类不允许有static...

前言

这是个好问题,因为它让我想起来自己刚学到内部类时候的“想用的冲动”。

导致我代码里到处都是层层的内部类套嵌。不但经常搞得静态域错误一堆(内部类不允许有static成员字段),而且过一段时间自己都搞不清当初写的是什么。

一个很重要的设计准则是:设计是做减法,能不用模式就不用模式。

这个准则对内部类来说同样适用。

所以回答这个问题的基调应该是:

能不用内部类就不用内部类。

实践

我以前觉得内部类用来有针对性地暴露外部类的特定接口,比一下子把整个对象都给人家要好。比如说下面代码中的外部类outer实现了三个接口方法,能跑,能飞,能思考。然后有三个方法getrunner(),getflyer(),getthinker()有针对性地对外暴露部分功能接口。

 public interface runnable{ public void run(); } public interface flyable{ public void fly(); } public interface thinkable{ public void think(); } public class outer{
 public void run(){ //do something } 
 public void fly(){ //do something }
 public void think(){ //do something } 
public class runner implements runnable{ 
public void run(){outer.this.run();} } 
public class flyer implements flyable{ 
public void fly(){outer.this.fly();} } 
public class thinker implements thinkable{ 
public void think(){outer.this.think();} } 
public runner getrunner(){return new runner();} public flyer getflyer(){return new flyer();} 
public thinker getthinker(){return new thinker();} } 

但实际上直接实现三个接口不是就很好嘛。用内部类根本算不上优雅,多了很多代码。仅仅为了暴露接口根本不需要使用内部类。

public interface runnable{ public void run(); } public interface flyable{ public void fly(); } public interface thinkable{ public void think(); } public class outer implements,runnable,flyable,thinkable{ 
public void run(){ //do something } 
public void fly(){ //do something } 
public void think(){ //do something } } 

再或者说常见的控制框架。我们定义个event接口,必须有action()方法。在外部类里定义事件处理的流程。然后定义了几个实现event接口的内部类。

public interface event{ public void action(); } public class controller{ 
private int id; 
private list<event> list=new arraylist<event>(); 
public void prepare(){ //put new events into the list } 
public void doevents(){ //do every events in the list } 
public class a implements event{ 
public void action(){ //do something } } 
public class b implements event{ 
public void action(){ //do something } } } 

但这也不是非内部类不可。独立定义a,b类,最后再把event对象组合到controller里完全可以,而且更简洁易读。

另外,说到内部类,经常会提到闭包,回调。但内部类也不是唯一的方案。简单的继承,组合都能实现同等的数据封装效果。

但java到底需不需要内部类?答案还是需要的。java引入内部类的真正意义就在于,还是有很多情况,没有内部类是处理不了的,或者用内部类处理起来更加优雅。

还是第一个例子。如果外部类不止有一种接口实现方法。如果我实现了runnable接口,就只能定义一个run()方法。这时候内部类就派用场了。比如,企鹅既会跑,又会游泳。所以它的两个内部类实现两种不同的run()。可以返回两种不同的runnable引用。

public interface runnable{ public void run(); } public class penguin{ 
public void run(){ //do something } 
public void swim(){ //do something } 
public class running implements runnable{
 public void run(){penguin.this.run();} } 
public class swimming implements runnable{ 
public void run(){penguin.this.swim();} } 
public runner getrunner(){return new running();} public flyer getswimmer(){return new swimming();} } 

另一种典型场景就是多继承。如果外部类已经继承了某个基类,比如说企鹅继承自鸟类。但runnable这时候正好是一个abstract抽象类呢?java不支持多继承,内部类可以解决这个问题。

public class bird{ //some code here } 
public abstract class runnable{ 
public abstract void run(); } 
public class penguin extends bird{ 
public class runner extends runnable{ //do something } 
public runner penguincanrun(){return new runner();} } 

刚才提到了控制框架可以不用内部类。但实际上你看看事件驱动的swing里到处都是内部类。为什么呢?因为有大量的事件,而且多数事件的相应方法只被用到了一次。用内部类是为了控制类的数量,考虑的是更好地封装。

内部类另外一个好的特性就是它独立于外部类,不会像组合一样随着外部类的初始化而一起被初始化。而是在我们需要它的时候再创建它。比如说容器里的迭代器,需要我们手动创建。作为可选组件存在于外部类中,不会增加外部类的负担。

总之,要知道什么时候真正需要内部类,先要搞清楚什么时候可以不用内部类。内部类不是大力丸,不要滥用内部类