Java 匿名内部类使用的外部变量,为什么一定要加 final?

news2024/11/30 0:44:24

问题描述

在这里插入图片描述
在这里插入图片描述

Effectively final

  • Java 1.8 新特性,对于一个局部变量或方法参数,如果他的值在初始化后就从未更改,那么该变量就是 effectively final(事实 final)。 这种情况下,可以不用加 final 关键字修饰。

在这里插入图片描述
在这里插入图片描述

内部类会持有外部类对象的引用

  • 非静态内部类,持有外部类的引用;
    • 以编译器自动生成的成员变量的形式持有
    • 通过编译器自动生成的构造方法传入
  • 静态内部类,不持有外部类的引用

内部类

非静态内部类会通过自动生成的构造函数持有一个外部类对象的引用:

在这里插入图片描述
在这里插入图片描述

即便给内部类增加一个非默认的构造函数,编译器依然会自动为构造函数添加一个外部类对象的参数:

在这里插入图片描述

静态内部类

静态内部类自动生成的构造方法不会持有外部类的引用:

在这里插入图片描述

匿名内部类

匿名内部类也会通过构造函数持有一个外部类对象的引用:

在这里插入图片描述
在这里插入图片描述

匿名内部类会将捕获的局部变量在其构造函数中传入:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

匿名内部类捕获外部变量添加 final 的作用是:保证匿名内部类捕获的副本引用和外部的局部变量始终都指向同一个对象,也就是没有人可以修改它们的指向。

在这里插入图片描述

假如外部方法的局部变量不加final,有可能外部的局部变量的指向改变了,但是内部类却不知道。这样就可能导致内部类操作的对象和外部的局部变量指向的不是同一个对象,会出现 bug。

注意:匿名内部类捕获的局部变量加 final 是指的处于同一方法内的局部变量如果捕获的是所处的外部类中的变量,则不需要加 final,这是因为在这种情况下,可以直接通过外部类对象的引用来获取到其成员变量。

在这里插入图片描述
在这里插入图片描述

总结

  • 匿名内部类,持有外部类的引用;
    • 以编译器自动生成的成员变量的形式持有
    • 通过编译器自动生成的构造方法传入
    • 匿名内部类,通过这个引用访问外部类的成员变量和方法
  • 匿名内部类,访问外部局部变量时,其实是访问自身的一个成员变量;
    • 这个成员变量,是编译器自动生成的;
    • 这个成员变量,由编译器自动生成的构造方法初始化;
    • 为了保证这个成员变量和外部局部变量时刻保持一致性,二者必须都是final的。

根本原因就是为了保证内部和外部对这个局部变量的对象的操作保持一致性因此要求两个副本均不可变。

Kotlin 的匿名内部类

kotlin 中的匿名内部类不会外部变量时,即便不使用类似final的关键字修饰也能保证内部和外部访问的同一局部对象的一致性。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过以上字节码分析可以得出结论:

  • Kotlin 的匿名内部类不会在构造函数中传入整个外部类对象的引用
  • 但是对于捕获的局部变量,会自动生成一个不可变(val)的保证类对象(ObjectRef)传入构造函数中。

对应的伪代码结构2如下:

在这里插入图片描述

ObjectRef 是什么:

在这里插入图片描述

我们看到它就是一个泛型类,内部持有一个 element泛型成员变量,可以认为是 Kotlin 为了解决捕获局部变量问题生成的一个装箱类

除了 ObjectRef,Kotlin 中还有 ByteRefShortRefIntRefLongRefFloatRefDoubleRefCharRefBooleanRef

所以虽然与 Java 的解决方式不同,但本质上看思想是一致的,都要保持内部和外部对捕获变量的操作一致性,即保证这两个副本的不可变性

在这里插入图片描述

虽然包装类对象的指向不可变,但是包装类对象里面包的东西是可以改变指向的,这一点比 Java 要优秀:

在这里插入图片描述

这一切都是编译器为我们自动实现的,但对于开发者而言,体验上就会跟 Java 有明显的不同:“Java 需要 final 捕获,但 Kotlin 不需要 val 捕获”,但这是一个错觉,实际上 Kotlin 也需要,只不过你看不到而已。

内存泄漏问题

内存泄漏的根本原因就是一个长生命周期的对象被一个短生命周期的对象所引用。

在这里插入图片描述

  • 一旦内部类对象被长生命周期对象引用,或自身生命周期过长,就会导致外部类无法被 GC 回收,因为它们在同一条引用链上,根据 GC Root 可达性分析算法判断为可达。
  • 比如在 Activity 中通过匿名内部类的方式创建的 HandlerAsyncTaskResultReceiver等。

解决方式:

  1. 不使用(匿名)内部类,将类的定义放在外部,显示的构造传参,并在外部类销毁时(如Activity.onDestroy())主动断开对外部类的引用(例如很多框架会提供解绑、反注册的API以便用户在页面销毁时进行调用)。
  2. 必须要使用内部类的场景,采用静态内部类 + 弱引用指向外部类对象的方式。(由于弱引用一旦被GC扫描发现就会回收,所以不存在内存泄漏问题)
    在这里插入图片描述

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

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

相关文章

计算机设备管理器如何看内存,怎么查看电脑配置信息?3种方法,让你掌握电脑全部信息!...

转载:https://blog.csdn.net/weixin_35849957/article/details/118512756?spm1001.2014.3001.5502 原标题:怎么查看电脑配置信息?3种方法,让你掌握电脑全部信息! 电脑的配置决定了电脑性能高低以及运行速度。而电脑…

Ubuntu22.04 LTS + CUDA12.3 + CUDNN8.9.7 + PyTorch2.1.1

简介 本文记录Ubuntu22.04长期支持版系统下的CUDA驱动和cuDNN神经网络加速库的安装,并安装PyTorch2.1.1来测试是否安装成功。 安装Ubuntu系统 如果是旧的不支持UEFI启动的主板,请参考本人博客U盘系统盘制作与系统安装(详细图解&#xff09…

深度学习基础介绍

定义: 深度学习是机器学习领域中一个新的研究方向,被引入机器学习使其更接近于最初的目标,即人工智能AI, Artifical Intelligence。 深度学习是学习样本数据的内在规律和表示层次,这些学习过程中获得的信息对诸如文字…

Docker网络架构介绍

本文主要介绍了Docker容器的单机网络架构与集群网络架构,辅以演示,并简单介绍了网络管理中的命令。 前文: Docker的安装与简单操作命令-CSDN博客 docker网络原理介绍 与ovs类似,docker容器采用veth-pair linux bridge (虚拟交…

CPU设计——Triumphcore——MP_work版本

该版本用作系统寄存器的实现,M/S/U状态的实现与切换,以及load/store的虚实地址转换 设计指标 2023.12.8 2023.12.9 不实现mideleg和medeleg,因此一旦出现异常,直接切换至M态, 调试记录 到存储区中取PTE要额外至少…

hive 命令行中使用 replace 和nvl2 函数报错

1.有时候在命令行的情况下使用 replace 函数时会报错 这个时候可以使用 translate 代替 2.有时候使用 nvl2() 函数的时候会报错 这个时候可以用 case when 来代替

IO / day06 作业

1.使用有名管道&#xff0c;完成两个进程的相互通信 代码&#xff1a; // 使用有名管道&#xff0c;完成两个进程的相互通信#include <myhead.h>// task sender void *tasks(void *arg) {printf("I am tasks\n");int fdw -1;const char **ppargv (const c…

Redis核心知识点总结

1.Redis介绍 Redis 是 NoSQL&#xff0c;但是可处理 1 秒 10w 的并发&#xff08;数据都在内存中&#xff09; 使用 java 对 redis 进行操作类似 jdbc 接口标准对 mysql&#xff0c;有各类实现他的实现类&#xff0c;我们常用的是 druid 其中对 redis&#xff0c;我们通常用 J…

链表面试题的总结和思路分享

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

Vite4、Vue3、Axios 针对请求模块化封装搭配自动化导入(简单易用)

针对请求模块化封装搭配自动化导入&#xff08;简单易用&#xff09; 目标目录目标代码前提步入正题src / utils / index.jssrc /api / index.jssrc /api / request.jssrc /api / service.jssrc /api / utils.jssrc /api / modules / demo.js 自动化配置vite.config.jseslint 校…

《PySpark大数据分析实战》-01.关于数据

&#x1f4cb; 博主简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是wux_labs。&#x1f61c; 热衷于各种主流技术&#xff0c;热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员&#xff08;PCTA&#xff09;、TiDB数据库专家&#xff08;PCTP…

VSCode安装与使用

VS Code 安装及使用 1、下载 进入VS Code官网&#xff1a;地址&#xff0c;点击 DownLoad for Windows下载windows版本 注&#xff1a; Stable&#xff1a;稳定版Insiders&#xff1a;内测版 2、安装 双击安装包&#xff0c;选择我同意此协议&#xff0c;再点击下一步 选择你…

jquery实现省市区三级联动

一、技术: 前端采用的是jsp页面 后端采用springmvc+mybatis+mysql8 效果图 二、cascadeSelect.jsp页面 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%String path = request.getContextPath();String basePath = r…

流程画布开发技术方案归档(G6)

&#x1f3a8; 在理想的最美好世界中&#xff0c;一切都是为最美好的目的而设。 —— 伏尔泰 如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; 一、技术选型 •从可维护性和可拓展性出发 •基本满足 1&#xff1a;链接: https://github.com/hukaibaihu/vue-org…

Java 手写设计HashMap源码,让面试官膜拜

Java 手写HashMap源码&#xff0c;让面试官膜拜 一&#xff0c;手写源码 这是一个模仿HashMap的put&#xff0c;get功能的自定义的MyHashMap package cn.wxs.demo;import java.io.Serializable; import java.util.*; import java.util.function.BiConsumer;class MyHashMap&…

【解密考研英语:Python数据分析与可视化】

解密考研英语&#xff1a;Python数据分析与可视化 背景数据集技术选型功能实现创新点 大家好&#xff0c;欢迎阅读我的CSDN博客&#xff01;今天我将分享一项有关考研英语真题的数据分析与可视化项目&#xff0c;希望对考研学子提供更有针对性的复习帮助。 背景 作为考研学子…

【TwinCAT学习笔记 1】TwinCAT开发环境搭建

写在前面 作为技术开发人员&#xff0c;开启任何一项开发工作之前&#xff0c;首先都要搭建好开发环境&#xff0c;所谓磨刀不误砍材工&#xff0c;一定要有耐心&#xff0c;一次不行卸载再装。我曾遇到过一个学生&#xff0c;仅搭建环境就用了两周&#xff0c;这个过程也是一…

Docker容器的可视化管理工具—DockerUI本地部署与远程访问

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

3接上篇 我的自定义GPTs的改进优化 与物理世界连接成功 GPTs的创建与使用定义和执行特定任务的功能模块 通过API与外部系统或服务的交互

https://blog.csdn.net/chenhao0568/article/details/134875067?spm1001.2014.3001.5502 从服务器日志里看到请求多了一个“location” 23.102.140.123 - - [08/Dec/2023:14:02:20 0800] "GET /getWeather.php?location&locationNewYork HTTP/1.1" 200 337 &…

公式识别任务各个链条全部打通

目录 引言公式识别任务是什么&#xff1f;公式识别任务解决方案初探使用建议写在最后 引言 随着LaTeX-OCR模型转换问题的解决&#xff0c;公式识别任务中各个链条已经全部打通。小伙伴们可以放开膀子干了。 解决业界问题的方案&#xff0c;并不是单独训练一个模型就完事了&am…