看到下面的问答,有同学问,在讲使用线程池执行大量的Runnable命令时,案例中局部变量n的final为什么要加:
相关连接:https://blog.csdn.net/xiaobei3120/article/details/12747117
帖子里提到了:
匿名内部类一般定义在一个方法的内部,如果要访问该方法的参数或者方法中定义的变量,则这些参数或者变量必须使用final修饰。
虽然匿名内部类定义在方法的内部,但在编译时内部类与外部类中的方法属于同一个级别,外部类中方法的变量或参数只是方法的局部变量,这些变量或者参数的作用域只在当前方法内部有效。但是如果这些变量用final修饰,内部类就可以保存方法变量的备份,即使方法销毁也能保证内部类在访问时不会出现访问不到的错误。
匿名内部类要访问局部变量,但是函数的局部变量在执行完后会立即退出,销毁掉所有临时变量。而产生的匿名内部类可能会保留.
实际上:匿名内部类并不是直接调用的局部变量n,而是内部类将局部变量n通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数。 这样理解就很容易得出为什么要用final了,因为两者从外表看起来是同一个东西,实际上却不是这样,如果内部类改掉了这些参数的值也不可能影响到原参数,然而这样却失去了参数的一致性,因为从编程人员的角度来看他们是同一个东西,如果编程人员在程序设计的时候在内部类中改掉参数的值,但是外部调用的时候又发现值其实没有被改掉,这就让人非常的难以理解和接受,为了避免这种尴尬的问题存在,所以编译器设计人员把内部类能够使用的参数设定为必须是final来规避这种莫名其妙错误的存在。
并且JDK1.8之后匿名内部类访问方法中的局部变量不用加final修饰.
以上是关于匿名内部类中使用方法当中的变量的问题。顺便研究一下匿名内部类:
思考到了一个问题,那我们可以自己在敲代码的时候在匿名内部类里面定义匿名内部类自己的构造器吗 ?
第一步:研究一下,匿名内部类到底是不是执行了父类的构造器。
查资料:https://www.cnblogs.com/wzhanke/p/4779048.html
这个帖子让我们了解到,编译的时候会给匿名内部类生成自己的字节码文件(.class结尾),并且这个字节码文件当中包含外部类的引用,包含自己的构造器,也就是下面的图片代码第5行的构造器。
通过帖子对帖子中的字节码文件的解读。我们可以发现,第12行:
7: invokespecial #2; //Method Test."<init>":(I)V 这个位置 应该是执行了匿名内部类父类Test的构造器。在帖子作者的案例中匿名内部类的父类是Test类。
也就是说,匿名内部类实际上是执行了父类的构造器的。
第二步: 上一步已经证明了无参数构造器。那么匿名内部类可以调用父类的有参数构造器吗?也就是在创建匿名内部类对象的时候可以传参吗?
思考:我可以在下面的Inter后的小括号,(写着xxx的那个括号)里面传入参数吗?,xxx是我的参数,如下代码:
new Inter(xxx){
...方法的重写等等操作
}
是否能传取决于Inter这个父类,Inter是我们定义的匿名内部类的父类,或者是接口。
如果Inter是一个类,或者抽象类,并且这个类或者抽象类里定义了有参构造器,那么我们在写匿名内部类的时候,匿名内部类就可以传参数。(通过上面的第一步的帖子分析可推断,如果创建匿名内部类对象的时候指定了xxx的值,也就是传参了,那么编译器就会调用父类的带同参数类型的有参构造方法)
如果Inter是一个接口,接口不能定义有参及无参数构造器,所以匿名内部类的那个位置就不可以传参数。
帖子:https://blog.csdn.net/ggjjzhzz/article/details/321272
这个帖子验证了这上面说到的,传参的问题,并且给了总结:
一、由于匿名内部类没有名字,所以它没有构造函数。因为没有构造函数,所以它必须完全借用父类的构造函数来实例化,换言之:匿名内部类完全把创建对象的任务交给了父类去完成。
二、在匿名内部类里创建新的方法没有太大意义,但它可以通过覆盖父类的方法达到神奇效果,如上例所示。这是多态性的体现。
三、因为匿名内部类没有名字,所以无法进行向下的强制类型转换,持有对一个匿名内部类对象引用的变量类型一定是它的直接或间接父类类型。
所以经常在定义匿名内部类的时候会给出下面的格式:感觉好像调用的是父类的构造器。
new 父类构造器(实参列表) | 实现接口()
{
//匿名内部类的类体部分
}
第三步:回到一开始的问题:
思考: 那我们可以自己在敲代码的时候在匿名内部类里面定义匿名内部类自己的构造器吗 ?
答案是:不可以。其实使用的时候编译器帮我们生成了构造器,但是我们自己不能写,因为匿名匿名,匿名的含义就是根本不知道这个类的名字是什么。
匿名内部类里面不可以定义自己的构造器,因为匿名内部类是要扩展或实现父类或接口,所以根本无法为其构造器命名(不能用父类名,哪有在子类里给父类写构造器的说法。而子类根本没有名,更别提用子类名做构造器了)。、因此在匿名内部中要想有构造器作用的部分要就应该是“初始化块”。
也就是说如果要初始化匿名内部类对象,可以采用构造代码块进行初始化。也就是 { }