为什么局部内部类和匿名内部类只能访问 final 的局部变量?
首先,我们看一个局部内部类的例子:
class OutClass {
private int age = 12;
public void outPrint(final int x) {
class InClass {
public void InPrint() {
System.out.println(x);
System.out.println(age);
}
}
new InClass().InPrint();
}
}
这里有一个外部类 OuterClass 和一个内部类 InClass,内部类访问了外部类的一个方法中的一个局部变量 x,在这里,x 必须是 final 的,否则会报错:
Cannot refer to a non-final variable x inside an inner class defined in a different method
下面来分析下这个问题:
追究其根本原因就是作用域中变量的生命周期导致的;
首先需要知道的一点是: 内部类和外部类是处于同一个级别的,内部类不会因为定义在方法中就会随着方法的执行完毕就被销毁。
这里就会产生问题:当外部类的方法结束时,局部变量就会被销毁了,但是内部类对象可能还存在(只有没有人再引用它时,才会死亡)。这里就出现了一个矛盾:内部类对象访问了一个不存在的变量。为了解决这个问题,就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡后,内部类仍可以访问它,实际访问的是局部变量的"copy"。这样就好像延长了局部变量的生命周期。我们可以通过反编译生成的 .class 文件来实验:
在命令行窗口中先执行命令 javac OutClass.java 进行编译,会得到两个文件: OutClass$1InClass.class、OutClass.class:

javap 是 Java class 文件分解器,可以反编译,也可以查看java编译器生成的字节码。
这里我们可以再执行命令 javap -privateOutClass$1InClass 进行反编译, -private 表示显示所有类和成员,执行后会得到如下结果:

可见方法中的局部变量实际上确实会复制为内部类的成员变量使用。
问题又出现了:将局部变量复制为内部类的成员变量时,必须保证这两个变量是一样的,也就是如果我们在内部类中修改了成员变量,方法中的局部变量也得跟着改变,怎么解决问题呢?
就将局部变量设置为final,对它初始化后,我就不让你再去修改这个变量,就保证了内部类的成员变量和方法的局部变量的一致性。这实际上也是一种妥协。
若变量是final时:
若是基本类型,其值是不能改变的,就保证了copy与原始的局部变量的值是一样的;
若是引用类型,其引用是不能改变的,保证了copy与原始的变量引用的是同一个对象。
这就使得局部变量与内部类内建立的拷贝保持一致。
原文链接:https://blog.csdn.net/sf_climber/article/details/78326984
为什么局部内部类和匿名内部类只能访问 final 的局部变量?的更多相关文章
- Java学习笔记23---内部类之局部内部类只能访问final的局部变量
局部内部类是定义在方法体或代码块中的类,在笔记19中已有过简单介绍. 今天要讨论的是局部内部类为什么只能访问为常量的局部变量. 作者: 博客园--蝉蝉 请尊重作者劳动成果,转载请在标题注明“转载”字样 ...
- Java 匿名内部类 只能访问final变量的原因
文章来源:http://blog.sina.com.cn/s/blog_4b6f8d150100qni2.html 1)从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方 ...
- 为什么匿名内部类只能访问final变量【转】
是变量的作用域的问题,因为匿名内部类是出现在一个方法的内部的,如果它要访问这个方法的参数或者方法中定义的变量,则这些参数和变量必须被修饰为final.因为虽然匿名内部类在方法的内部,但实际编译的时候, ...
- 局部内部类为什么只能访问final局部变量,对于成员变量却可以随便访问?
局部内部类为什么只能访问final局部变量,对于成员变量却可以随便访问? public class OuterClass { private int memberField = 10; public ...
- Java基础_内部类、静态内部类、成员内部类、局部内部类、匿名内部类 (转)
From: http://www.itzhai.com/java-based-notebook-a-static-inner-class-within-a-class-member-within-th ...
- Java:内部类(静态内部类、成员内部类、局部内部类、匿名内部类)
Java基础_内部类:在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类. 内部类的主要作用:使用内部类可以减少命名冲突. 定义位置:一个内部类可以定义在一个类中,也可以 ...
- Java中的内部类(成员内部类、静态内部类、局部内部类、匿名内部类)
Java中的内部类(成员内部类.静态内部类.局部内部类.匿名内部类) 神话丿小王子的博客主页 我们先看这样一段话:人是由大脑.肢体.器官等身体结果组成.而组成我们人体的心脏它也有自己的属性和行为(血液 ...
- Java学习笔记19---内部类之简介成员内部类、局部内部类及匿名内部类
内部类,顾名思义,即定义在某个类内部的类,称包含该内部类的类为外部类. 从定义的位置来说,分为成员内部类和局部内部类:从类的特征来说,分为匿名内部类和静态内部类. 今天先简要介绍一下前三种内部类的定义 ...
- 匿名内部类为什么访问外部类局部变量必须是final的?
1.内部类里面使用外部类的局部变量时,其实就是内部类的对象在使用它,内部类对象生命周期中都可能调用它,而内部类试图访问外部方法中的局部变量时,外部方法的局部变量很可能已经不存在了,那么就得延续其生命, ...
随机推荐
- argmax( )
argmax是一种函数,是对函数求参数(集合)的函数. 当我们有另一个函数y=f(x)时,若有结果x0= argmax(f(x)),则表示当函数f(x)取x=x0的时候,得到f(x)取值范围的最大值: ...
- AcWing 907. 区间覆盖
//1.将所有区间按照左端点从小到大排序 //2.从前往后依次枚举每个区间 //首先选择能够覆盖左端点的区间当中右端点最靠右的端点 //在所有能覆盖start的区间当中,选择右端点最大的区间 //选完 ...
- [linux] Ubuntu18.04 安装mysql密码不对
安装 安装过程可以说是非常简单了 sudo apt-get install mysql-server 然后看看有没有启动成功 systemctl status mysql 看到状态是 running就 ...
- 【C语言】数组名作函数参数,完成数据的升序排列
#include<stdio.h> void sort(int x[],int n); int main() { ] = { ,,,,,,,,, },i; sort(arr, ); pri ...
- hdu 6214 Smallest Minimum Cut(最小割的最少边数)
题目大意是给一张网络,网络可能存在不同边集的最小割,求出拥有最少边集的最小割,最少的边是多少条? 思路:题目很好理解,就是找一个边集最少的最小割,一个方法是在建图的时候把边的容量处理成C *(E+1 ...
- 001.Django_Model.整理
Django001_Model.整理 Model表设计 数据定义数据存储,输出 a.定义表(信息 =字段) + 定义表关系 + (定义/限制)数据 b.通过orm等方法来,定义method来编辑原始数 ...
- Oracle 11G统计信息自动收集及调整
查询统计信息的收集所对应的task,以及当前状态 col CLIENT_NAME for a50col TASK_NAME for a20SELECT client_name, task_name, ...
- bugku 管理员系统
这一个是伪造ip X-FORWARDED-FOR:127.0.0.1 用到了XFF头 首先打开网站会发现一个登录界面 然后用开发者工具看一下 后台会发现一串用base64加密的密文 用base64解密 ...
- 一起学Netty(一)之HelloWorld,可以聊天的小程序哦
转自于:http://blog.csdn.net/linuu/article/details/51306480
- Panda的学习之路(2)——pandas选择数据
首先定义panda dates=pd.date_range(',periods=6) # print(dates) df=pd.DataFrame(np.arange(24).reshape(6,4) ...