起因是每次在子线程调用局部变量时编译器爆红,要求参数改为final数组类型,今天心血来潮特地研究一下为什么必须得用final修饰。
当我们在子线程调用局部变量时编译器就会提醒我们
变量 'test' 在内部类中被访问,需要被声明为 final 或者是事实上的不可变。 当我们添加了final时
将'test'转换为最终的单元素数组
编译器就像一个非常谨慎的管家,总是想要确保你的代码不会闯入奇怪的麻烦。它有点像一个小摄影师,总是让你的代码在镜头前保持最佳状态。当你告诉它要将变量声明为 final 时,它感觉你是在为变量贴上“不可改变”的标签。但是,有时候你可能真的需要在代码中对变量做一些小改动,这时编译器就会变得像一个幽默的小丑,对你说:“哎呀, final 可不是那么容易使用的,得来点儿小花招。” 所以,你加了 final 后,编译器就告诉你,想使用 final 变量,得来点儿“小花招”,比如用数组。这就像你告诉编译器你想做一些小修饰,编译器回应:“哦,你是想要点特色吗?来试试用数组吧,这样我就会觉得你很时尚。”
首先我们知道final(保护数据的一致性),这里的一致性指对引用变量的一致性,对基本类型来说就是值的一致性。
使用 final 修饰变量可以保护数据的一致性,因为它确保在多线程环境中不会出现竞态条件或不一致的状态。在多线程编程中,多个线程同时访问和修改共享变量可能会导致数据不一致的问题,因为线程之间的操作顺序是不确定的。通过使用 final 修饰变量,可以在以下几个方面保护数据的一致性:
当一个变量被声明为 final 后,它的值就不能再被修改。但在一些情况下,我们可能需要在不修改变量本身的前提下,改变其所持有的值。这时,可以使用数组来解决这个问题。 使用数组的主要原因是,数组是引用类型,而 final 关键字只保证引用本身不会被改变,但并不限制引用所指向的对象的内容。因此,我们可以通过将变量声明为指向数组的 final 引用,然后在数组中改变元素的值,达到在 final 变量的限制下修改值的目的。 这种方式相当于“绕过”了 final 关键字的限制,因为数组的引用本身是 final 的,但数组中的元素可以被修改。这在一些需要在不改变变量本身的前提下,改变其持有的值的场景中很有用。 举例来说,如果你需要在一个匿名内部类中修改一个被声明为 final 的变量,可以将该变量包装在一个数组中,并将数组引用声明为 final。然后,在内部类中,你可以修改数组中的元素,从而实现修改值的目的,同时遵循 final 变量的限制。
在之前的Java版本中,当局部变量被匿名内部类引用时,编译器要求该变量为 final 或隐式的 final。这是因为匿名内部类(子线程也算一种匿名内部类)可能会在外部方法执行完毕后继续存在,而局部变量的生命周期通常在方法执行完毕后结束。这可能导致匿名内部类访问无效的变量。 为了解决这个问题,编译器要求变量为 final,这样在匿名内部类中会创建一个拷贝作为成员变量,确保变量的有效性。这样做的好处是,即使局部变量已经消失,匿名内部类仍然可以使用这个不变的成员变量。 然而,在JDK 8之后,编译器对内部类访问外部方法的局部变量进行了改进。不再需要显式声明为 final,因为编译器会自动添加 final 修饰。这使得代码更加简洁,减少了程序员的工作量。