【Java面试】为什么匿名内部类只能访问外部类的final类型局部变量?

news2024/11/17 11:47:31

先来看一下下面一段代码

public class InnerClassTest {
    public static void main(String[] args) {
        int a = 10;
        new Service() {
            @Override
            public void method() {
                System.out.println("a=" + a);
            }
        }.method();
        a = 11;
    }

}

interface Service {
    public void method();
}

这段代码并不能通过编译,因为他会抱有如下异常:
在这里插入图片描述
这里发现,我的匿名内部类调用外部的局部变量的时候发生了报错,那么这个报错的原因是什么?
我们先来看解决这个报错的方法:
1:删掉下面的对a=11的修改,这意味着a这个值并没有被修改,是只读的
2:将a变量设定为final类型
两种方法都能解决上面的问题,但是为什么我们使用外部的局部变量的时候我们需要它是未被修改的或者说为什么必须是final的?

答:

匿名内部类无法直接访问外部类方法中的局部变量,除非该变量被声明为final类型,是因为匿名内部类在实例化时会隐式地持有对外部类方法中的局部变量的引用。为了确保引用的可用性和一致性,Java编译器要求局部变量必须是final类型的。

当一个局部变量被声明为final时,Java编译器会在内存中创建一个拷贝,而不是直接引用原始变量。这样做的目的是为了避免匿名内部类中对外部局部变量的修改导致不一致的情况发生。

通过将局部变量声明为final,Java编译器确保了匿名内部类在获取局部变量的值时,能够获取到该变量的固定值。这样,即使外部方法调用已经结束,局部变量仍然可以正确地被匿名内部类所访问和使用。

需要注意的是,在Java 8之后,如果局部变量被显式声明为final,即使没有使用final关键字,同样可以在局部类或匿名内部类中访问。这是因为Java 8引入了"effectively final"的概念,即在变量被赋值后,没有再发生修改。在这种情况下,编译器会将其视为final类型的变量,从而允许在局部类或匿名内部类中访问该变量。这也就是为什么上面我们只要把a=11这一行代码删掉也可以通过运行的原因。
当然,如果你的JDK版本是7或者更早,那么就依旧会报错,如下:
在这里插入图片描述
面试官:为什么匿名内部类只能访问外部类的final类型局部变量?

我对这个问题的完整解释是这样子回答的

我:其实对于为什么需要使用final类型的外部局部变量,我的解释应该会倾向于生命周期的概念。

我们知道,匿名内部类的调用发生在方法中,方法创建时会创建一个栈帧,栈帧中保存的是我们的局部变量等信息,这个时候如果我们使用了匿名内部类,还会再堆中创建一个类,然后如果我们的这个匿名内部类使用了外部变量,而外部变量的创建是跟随方法的,如果方法结束,那么外部变量就要被回收消失,此时会出现生命周期的问题,也就是我们的匿名内部类还指向这个方法,并且内部类还没有被回收,因为堆内对象的回收需要的是垃圾回收器的工作而不是跟随方法,即使这个对象是通过这个方法才创建的。

因此此时就会出现外部变量消失的情况,而匿名内部类依旧存在于堆内存中并且对外部变量存有引用,为了解决这种生命周期不一致的问题,可以使用final关键字修改局部变量的生命周期,我们知道如果对局部变量使用final修饰,他就会在内存中留有一份数据。

当局部变量被声明为final时,它们在内存中会保留其值。在使用final修饰的局部变量时,其值在声明时被确定,并且不能再被修改。这样做的目的是为了确保在匿名内部类或其他类的方法中使用这些final变量时,它们的值保持不变。

在编译过程中,如果一个局部变量被匿名内部类或其他闭包引用,编译器会创建一个新的内部类,并将这些被引用的final局部变量的值传递给内部类的构造函数。因此,这些final局部变量的值将在内存中一直存在,直到内部类对象不再被引用,并由垃圾回收器回收。

值得注意的是,如果局部变量没有被匿名内部类或其他闭包引用,即使将其声明为final,它们在方法执行完毕后仍然会被销毁,不会一直保存在内存中。只有在有需要的情况下才将局部变量声明为final。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/696191.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

官宣自营品质快递服务,菜鸟显露“鸿鹄之志”?

菜鸟迎来分拆发展后又一重磅动作。6月28日,菜鸟在全球智慧物流峰会现场,宣布推出自营的品质快递业务:菜鸟速递。菜鸟集团CEO万霖确认,已经获得“快递牌照”。 菜鸟速递的推出处于一个特殊的背景下,它作为阿里拆分后上…

114.简单介绍JavaScript

首先我们复制我们的起始js代码 css /// // Fixing flexbox gap property missing in some Safari versions function checkFlexGap() {var flex document.createElement("div");flex.style.display "flex";flex.style.flexDirection "column"…

内核链表的使用

目录 📎list.rar 链表的作用 使用list.h使用例 练习 答案: 📎list.rarhttps://www.yuque.com/attachments/yuque/0/2023/rar/35243076/1687947573309-b0609eda-c0ac-475d-8d13-b901a3359cad.rar 链表的作用 链表在动态内存分配、插入删…

【前端工程化】Docker入门

背景 当我们使用(开发)某个软件,可能得确保操作系统、依赖、环境变量相同的问题,这些配置可能就需要花费很多时间。使用虚拟机,可以解决上述部分问题,但是它又引发了其他问题:资源占用多、冗余…

星辰秘典:揭示Python项目的宇宙奥秘——宇宙星空模拟器(改)

✨博主:命运之光 🌸专栏:Python星辰秘典 🐳专栏:web开发(html css js) ❤️专栏:Java经典程序设计 ☀️博主的其他文章:点击进入博主的主页 前言:你好&#x…

2.7C++基类和派生类转换

C 基类和派生类转换 C中基类与派生类之间的转换有两种方式: 1、向上转换 向上转换是将派生类的指针或引用转换为基类的指针或引用。 向上转换是安全的,因为基类是派生类的公共部分,可以保证派生类对象的所有成员都可以被基类指针或引用访…

Windows11 anaconda配置pytorch环境

生成 .condarc 文件,位于C:\Users\Admin\ conda config --set show_channel_urls yes 记事本打开 .condarc 文件,添加以下内容: channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ - https://mirrors.tuna.tsingh…

北上广深共享办公室市场概览

在北上广深这四个城市,共享办公室已经成为一种日益流行的办公模式。随着经济的快速发展和科技创新的不断推进,越来越多的企业开始青睐共享办公室,以适应灵活办公和协作办公的需求。那么,2023年共享办公室市场的前景如何呢&#xf…

头条搜索精选 参数分析

本文所有教程及源码、软件仅为技术研究。不涉及计算机信息系统功能的删除、修改、增加、干扰,更不会影响计算机信息系统的正常运行。不得将代码用于非法用途,如侵立删!头条搜索精选 参数分析 环境 win10Python3.9Chrome抓包接口分析 主要是需要这一块的内容 通过抓包分析发…

一、机器学习概述

一、机器学习概述1.机器学习初步认识2.机器学习类型1)监督学习a.分类b.回归 2)无监督学习a.聚类b.降维 3.机器学习方法1)模型2)损失函数3)优化算法4)模型评估指标 4.开发流程 一、机器学习概述 1.机器学习初…

Openlayers图文版实战,vue项目从0到1做基础配置

Openlayers的实战教程 分为**图文版** 和 **视频版**, 这里的是图文版,包含基础知识介绍和*实战的源代码*,示例效果以gif动图的形式展现出来。 **视频版** 正在录制中,很快会上线,敬请期待~, 如有问题&am…

Java如何实现手动连接数据库(Mysql或Oracle) | 超级详细,建议收藏

👨‍🎓作者:bug菌 ✏️博客: CSDN、 掘金、 infoQ、 51CTO等 🎉简介:CSDN博客专家,C站历届博客之星Top50,掘金/InfoQ/51CTO等社区优质创作者,全网粉丝合计10w&#xff0c…

ant design vue 配置菜单外部打开

实现如下 菜单配置 前端项目地址:http://localhost:3000 菜单路径:dataCenter/HealthData 打开方式:外部 在项目中src-->config-->router.config.js文件 将需要再外部打开的菜单地址进行如下配置 菜单地址:/dataCenter/Hea…

软件测试面试题(完整版)

1、B/S架构和C/S架构区别 B/S 只需要有操作系统和浏览器就行,可以实现跨平台,客户端零维护,维护成本低,但是个性化能力低,响应速度较慢 C/S响应速度快,安全性强,一般应用于局域网中&#xff0c…

力姆泰克LBP滚珠丝杠电动推杆

LBP滚珠丝杠电动推杆 内含长寿命润滑脂,免维护 向下翻动查看更多 力姆泰克电动推杆 高强度/高耐磨材料选择,高精度的零部件加工,先进的壳体设计理念,造就高承载能力,抗冲击,低噪音,长寿命的优…

【AUTOSAR】BMS开发实际项目讲解(八)----BMS热管理冷却功能

热管理参数 项目 模式 BEV 进入条件(℃) 退出条件(℃) 目标水温(℃) 目标流速(L/min) 冷却 一级冷却 行车 T1_in35 T1_out28 20 20 快充 T1_in30 T1_out…

Vue3 刨析响应式 ref 原理

目标 了解 Vue ,手写一个方法,实现响应式,并读懂响应式 源码 class MyRef {constructor(value) {this._value value}// 访问器get value() {console.log(触发 getter 函数 访问);return this._value}// 读取器set value(newVal) {console.l…

微电网数字化系统硬件设备在储能行业中的应用

安科瑞虞佳豪 1如果说火爆的储能行业堪比新能源赛道上的皇冠,那么工商业储能就是皇冠上的明珠。 提及储能,人们习惯更多地关注源网侧储能电站(大储)身上,探讨发电侧配储、利用率、共享储能模式等话题,但其…

不一般!R型变压器直流电阻和绝缘电阻背后的秘密原来是这样!

一般来说,除了技术人员之外,我们可能不太清楚变压器的一些内部电阻,比如什么是R型变压器的直流电阻?事实上,这些都是变压器参数中的一些重要信息,通常与变压器的质量和使用有关。让我们和小r一起来看看什么…

AR项目问题汇总

1、unity使用URP 导致ARFoundation黑屏 (16条消息) unity使用URP 导致ARFoundation黑屏_arfoundation运行iphone黑屏_weixin_46813963的博客-CSDN博客https://blog.csdn.net/weixin_46813963/article/details/117509322Configuring the AR Camera background using a Scriptab…