在上一篇详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,在这篇博客中你可以了解到匿名内部类的使用、匿名内部类要注意的事项、如何初始化匿名内部类、匿名内部类使用的形参为何要为final。
匿名内部类由于没有名字,所以它的创建方式如下:
使用匿名内部类我们必须要继承一个父类或实现一个接口,事实上我们也只能这么做。同时它也没有class关键字,因为它是用new来生成一个对象的引用,并且这个引用是隐式的。
在Test类中,test()方法接受一个Bird类型的参数,同时因为我们知道抽象类不能直接被实例化,必须要实现之后才能使用new关键字对其实例化,所以在main方法中我们直接使用匿名内部类来创建Bird实例(先 实现抽象类Bird,再用new创建Bird对象引用)。由于匿名内部类不能是抽象类,所以必须要实现它的抽象父类或是接口里面的所有抽象方法。
对于这段匿名内部类代码其实是可以拆分为如下形式:
在这里系统会创建一个继承自Bird类的匿名类的对象,该对象转型为对Bird类型的引用。
同时需要注意的是:匿名类只能被使用一次,创建匿名内部类时它会立即创建一个该类的实例并,类的定义会立即消失,所以匿名内部类是不能被重复使用的。如果我们需要对匿名内部类进行多次使用,则不建议使用匿名内部类,而要重新定义其它的类。
1.匿名内部类必须继承一个类或实现一个接口,同时也只能这么做,但两者不可兼得;
2.匿名内部类不能有构造方法,因为它没有名称;
3.匿名内部类不能有static修饰的成员变量和方法;
4.匿名内部类属于局部内部类,所以局部内部类的所有限制同样对匿名内部类有效;
5.匿名内部类不能是抽象的,它必须实现它所继承的抽象类和它所实现的接口中的所有的抽象方法。
我们在给内部类传递参数的时候,如果传递的形参要被内部类使用,那么这个形参要被定义为final,为什么一定要为final呢?
我们知道,在内部类编译成功后它会产生一个classes文件,该classes文件与外部类的classes并不是同一个文件,仅仅只是保留对外部类的引用。当外部类传入的参数需要被内部类调用时,从java程序的角度来看是直接被调用:
从上面代码中看好像name参数应该是被内部类直接调用?其实不然,在java编译之后实际的操作如下:
所以从上面代码来看,内部类并不是直接调用方法传递的参数,而是利用自身的构造器对传入的参数进行备份,自己内部方法调用的实际上是自己的属性而不是外部方法传递进来的参数。
直到这里还没有解释为什么是final?在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看是不可行的,毕竟站在程序员的角度来看这两个根本就是同一个,如果内部类改变了,而外部方法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的一致性,就规定使用final来避免形参的不改变。
简单理解就是,拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变。
故如果定义了一个匿名内部类,并且希望它使用一个其外部定义的参数,那么编译器会要求该参数引用是final的。
我们一般都是利用构造器来完成某个实例的初始化工作的,但是匿名内部类是没有构造器的!那怎么来初始化匿名内部类呢?使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果。
以上内容均来自http://www.cnblogs.com/chenssy/博客,此博客为本人学习笔记