为什么Java匿名内部类或者lambda访问的方法参数或方法局部变量需要被final修饰

1.内部类如果出现在外部类的非方法里, 内部类可安全的访问类中所有变量。
2.内部类如果出现在外部类的某方法A里(java语法规定只可能是匿名内部类), 那么需要解决一个问题: A方法执行完毕就弹栈了, 局部变量不存在了, 匿名内部类在访问此A方法参数或者A方法局部变量的时候, 该如何做? 这个问题即 内部类的实例(对中的地址值)的生命周期有可能超过局部变量的生命周期(栈中的变量)(此场景即所谓的闭包,在javascript等很多语言中都有)。典型的是回调函数的场景: A方法直接把含有匿名函数的对象返回给外界, 这时候外界可以调用匿名函数, 但是A函数栈桢弹栈了, 也就是匿名函数依赖的局部变量销毁了

何解?
Java解决方法是将局部变量复制一份到内部类(也就是在内名类维护一个构造方法和几个成员变量来对应依赖的外部方法中的局部变量),这样方法执行完后匿名内部类里仍可使用该变量。但是复制就意味着要处理数据同步问题, 比如重新赋值了怎么办

何解?

  1. 真同步? 虚拟机累啊, 需要侦测变化, 通知再同步, 困难且麻烦
  2. 地址值不可变(大家指向同一片内存地址, 就算你改东西我也看得到, 只要你不改地址值就行)或者值不变不就行了, 就不用同步了. java final可以做到, 所以java8以前强制final, java8以后, 编译器会贴心的给你补final, 补完不报错, 也就是你没二次赋值, 这就是所谓的effictively final, 补完如果报错, 对不起, 请你不要二次赋值

lambda就是某种匿名内部类的语法糖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java 中使用 Map.forEach 在循环中,需要使用 final 修饰的常量数组是因为 forEach 方法使用的是内部迭代器,该迭代器使用了闭包的概念,闭包中可能会引用到外部的变量。如果不使用 final 修饰,则外部的变量可能会被修改,而在闭包中使用的这个变量的值可能会发生变化,这会导致结果的不确定性。因此,为了保证结果的可预测性和程序的正确性,Java 中的 forEach 方法要求使用 final 修饰的常量数组。 ### 回答2: 在Java中使用map.forEach时,循环体内的变量和参数必须是final修饰的常量数组,而不能使用基本类型和包装类型的原因如下: 1. map.forEach方法使用了Lambda表达式,Lambda表达式的特点是闭包,它可以捕获外部的变量。在循环体内部,Lambda表达式可能对外部的变量进行修改,因此外部的变量必须是不可变的,即final修饰的常量。 2. 对于基本类型和包装类型的值,赋值操作实际上是将新值赋给了一个新的变量,而原来的变量仍然指向原来的值。在循环体内部对基本类型和包装类型的变量进行修改操作,相当于修改了新变量的值,而不是原来的变量指向的值。因此,如果在循环体内部修改基本类型和包装类型的值,循环体外部的值不会受到影响。 3. Java中的基本类型和包装类型都是值传递,而不是引用传递。在循环体内部对基本类型和包装类型的变量进行修改,并不会影响到循环体外部的值。因此,为了保证循环体内部对变量的修改能够生效,必须使用final修饰的常量,以保证循环体内外的变量引用的是同一个对象。 综上所述,为了确保在使用map.forEach时,循环体内部对变量的修改生效,仅能使用final修饰的常量数组。这样可以保证循环体内外的变量引用的是同一个对象,从而使得循环体内部对变量的修改能够影响到循环体外部的值。 ### 回答3: 在Java中,当我们在forEach循环内部使用局部变量时,该变量必须是final修饰的常量数组,而不能是基本类型或包装类型。 这是因为forEach循环是通过迭代器来遍历集合,而迭代器在循环中是一个匿名内部类实现的。正常情况下,局部变量在栈上分配内存,当调用方法结束后,栈帧被销毁,局部变量也随之销毁。但是对于匿名内部类来说,它可能会在循环过程中被多次使用,而不像普通局部变量那样只有一次。所以,为了保证在匿名内部类中能够访问局部变量Java要求我们将局部变量声明为final,这样在内部类中就能够正确访问了。 但基本类型和包装类型在Java中有一个特点,即它们是值传递。这意味着,当我们将基本类型或包装类型作为参数传递给方法时,实际上传递的是其值的一个副本,而不是对原始值的引用。因此,在forEach循环内部使用final修饰的基本类型或包装类型并没有太大的实际意义,因为它们在循环中使用的是它们的副本,而不是原始值。 综上所述,为了在forEach循环中能够正确访问局部变量,我们需要将其声明为final修饰的常量数组。这样,在循环中我们使用的是该常量数组的引用,而不是对它的拷贝,这样就确保了匿名内部类能够正确访问到这个数组。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值