你可能在安卓中编写过如下程序,在内部类中试图捕获局部变量。但在Java1.8之前是不允许这样捕获的。
如果你非要捕获可变变量,可以使用下面两种技巧中的一个:
1. 声明一个单元素数组,其中储存可变值
2. 创建一个包装类的实例,存储要改变的值的引用。
思考: Java为什么要这么要求呢?
总的来说,为了保证内部类得到的局部变量的数据是一致的。假如上图代码中 变量out 在打印后修改,然后再次在外部打印out,这回造成不一致! 所以final是保证一致性。在Java1.8之后IDEA对此进行优化 默认对局部变量设置为final。
在Kotlin中,如若捕获可变值可以如下处理:
class Ref<T>(var value:T)
val counter = Ref(0)
val inc = { counter.value++ }
在实际代码中 可以直接如此编写:
var counter = 0;
val inc = {counter++}
原理是捕捉了一个val变量,他的值被copy下来,和Java一样,当捕获var值时,他被当成一个类的字段储存下来,该类的引用会是final的。
但是,在事件处理器或者监听时,捕获局部变量并修改只会在监听时发生,该声明内部类的方法一结束,但内部类生命周期并未终止,所以,对局部变量的修改只会在监听时生效!
如下并不是记录点击按钮的正确操作:
fun tryToCountButtonClicks(button:Button):Int{
var clicks = 0
button.onClick{ clicks++ }
return clicks //clicks始终返回0! 所以存储到成员变量较合适
}
参考 xiancaieeee https://blog.youkuaiyun.com/xiancaieeee/article/details/8834352