我们先稍微看一下代码:

从这里的提示可以看到,必须要将a的修饰符变为final才行。

现在笔者就这一结果做出自己的分析:

首先来说,我们知道,方法被调用时会执行,当执行的时候,方法中的局部变量会加载到栈内存中,方法执

行完毕后局部变量会从栈中被释放(会被垃圾回收器立即回收)。其次,当一个对象被new出来后,new出来的

对象生存再堆(堆中的对象在用完后不会马上被回收),对象的引用存在于栈中,也会立即被收回。 结合以上的

代码我们可以发现,当test方法执行完成后,int类型的a变量立即被回收了,A对象的引用a1也被立即回收了,但

是new出来的A对象还是生存在堆上面,这个时候问题就出来了,一个活着对象持有一个被回收的变量。java作

为一种强类型语言,这种情况是肯定不允许的。

接下来我们分析,为什么加final后就可以了呢?

我们先看下面两段话:


final修饰局部变量

final修饰的局部变量一样需要被显式地赋初始值,因为Java本来就要求局部变量必须被显式地赋初始值。与普通变量不同的是,final修饰的局部变量被赋初始值之后,将不能再被重新赋值。

final修饰符的第一简单的功能就是一旦被赋初始值,将不可改变。
final的另一个简单的功能就是在定义了该final类变量时指定了初始值,且该初始值可以在编译时就被确定下来,系统将不会在静态初始化块中对该类变量赋初始值,而将是在类定义中直接使用该初始化值代替该final变量。

对于一个使用final修饰的变量而言,如果定义该final变量时就指定初始值,而且这个初始值可以在编译时就确定下来,那么这个final变量将不再是一个变量,系统会将其变成“宏变量”处理。所有出现该变量的地方,系统将直接把它当成对应的值处理。
执行“宏替换”的变量

final修饰符的一个重要用途就是定义“宏变量“,当定义final变量时就为该变量指定了初始值,而且该初始值可以在编译的时候就确定下来,那么这个final变量本质上就是一个”宏变量“,编译器会把程序中所用到该变量的地方直接替换成该变量的值。如果被赋的表达式只是基本的算术运算表达式或字符串连接运算,没有访问普通变量,调用方法,Java编译器同样会将这种final变量当成”宏变量“处理。

对于实例变量而言,可以在定义该变量时赋初始值之外,还可以在非静态初始化块、构造器中对它赋初始值,在这三个地方指定初始值的效果基本一样。但对于final实例变量而言,只有在定义该变量时指定初始值才会有”宏变量“的效果,在非静态初始化块、构造器中为final实例变量指定初始值则不会有这种效果。对于普通类变量而言,在定义时指定初始值,在静态初始化块中赋初始值的效果基本一样。但对于final类变量而言,只有在定义final类变量时指定初始值,系统才会对该final类变量执行”宏替换“

文字总是没有代码直观,接着我把上面代码的class文件反编译后得到如下代码:

先将未编译的java代码贴上来以做比较:

package com.itheima;
// 这是测试类
 public class Test { public void test(){ final int a = 10; A a1 = new A(){ public void show(){
System.out.println(a);
}
};
}
}
package com.itheima;
// 就一个show方法
public interface A { public void show();
}

反编译字节码文件后得到以下代码:

package com.itheima;

import java.io.PrintStream;

public class Test
{
public void test()
{
int a = 10; A a1 = new A()
{
public void show()
{
System.out.println(10); //在编译后,匿名内部类中的a直接被替换成了10
}
};
}
}

通过以上分析结合之前的两段问题,我认为,用final修饰后,匿名内部类中所引用的局部变量将以字面值常量的

形式存在,方法运行结束后,虽然方法中的局部变量被回收了,但是在匿名内部类并不受影响。所以加final能解

决之前我们提出的问题。

从垃圾回收机制解析为什么局部内部类只能访问final修饰的局部变量以及为什么加final能解决问题的更多相关文章

  1. Java学习笔记23---内部类之局部内部类只能访问final的局部变量

    局部内部类是定义在方法体或代码块中的类,在笔记19中已有过简单介绍. 今天要讨论的是局部内部类为什么只能访问为常量的局部变量. 作者: 博客园--蝉蝉 请尊重作者劳动成果,转载请在标题注明“转载”字样 ...

  2. Android(java)学习笔记150:为什么局部内部类只能访问外部类中的 final型的常量

    为什么匿名内部类参数必须为final类型: 1)  从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形式参数定义处或者方法体处),因而访问方法中的局部变 ...

  3. Android(java)学习笔记93:为什么局部内部类只能访问外部类中的 final型的常量

    为什么匿名内部类参数必须为final类型: 1)  从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形式参数定义处或者方法体处),因而访问方法中的局部变 ...

  4. DAY20、垃圾回收机制,正则模块

    一.垃圾回收机制1.不能被程序访问到的数据,就称之为垃圾2.引用计数:每一次对值地址的引用都可以使该值得引用计数加1 每一次对值地址的释放都可以使该值得引用计数减一 当一个值的引用计数为0时,该值就会 ...

  5. java:面向对象(接口(续),Compareble重写,Comparator接口:比较器的重写,内部类,垃圾回收机制)

    接口: *接口定义:使用interface关键字 * [修饰符] interface 接口名 [extends 父接口1,父接口2...]{ * //常量的声明 * //方法的声明 * } *接口成员 ...

  6. 深入解析Java垃圾回收机制

    引入垃圾回收 哪些内存需要回收? 引用计数法 可达性分析 如何回收 Marking 标记 Normal Deletion 清除 Deletion with Compacting 压缩 为什么需要分代收 ...

  7. JavaScript 执行环境、作用域、内存管理及垃圾回收机制

    前言 JavaScript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存. [原理]找出那些不再继续使用的变量,然后释放其占用的内存.为此,垃圾收集器会按照固定的时间间隔( ...

  8. 【转载】Java垃圾回收机制

    原文地址:http://www.importnew.com/19085.html Java垃圾回收机制 说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联 ...

  9. JAVA的垃圾回收机制

    1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的 ...

随机推荐

  1. d3.js v4曲线图的拖拽功能实现Zoom

    zoom缩放案例 源码:https://github.com/HK-Kevin/d...:demo:https://hk-kevin.github.io/d3...: 原理:通过zoom事件来重新绘制 ...

  2. ATcoder E - Flatten 质因子分解求LCM

    题解:其实就是求n个数的lcm,由于数据特别大,求lcm时只能用质因子分解的方法来求. 质因子分解求lcm.对n个数每个数都进行质因子分解,然后用一个数组记录某个质因子出现的最大次数.然后累乘pow( ...

  3. C - League of Leesins

    乱搞一发,,竟然过了!!! 题目大意:输入一个整数n,然后n-2行,每一行3个数字,表示一个数组中连续的3个数字,然后将这3个数字的顺序打乱,然后再将这个n-2行打乱,要求还原数组. 题解:先找到前3 ...

  4. Go gRPC进阶-go-grpc-middleware使用(八)

    前言 上篇介绍了gRPC中TLS认证和自定义方法认证,最后还简单介绍了gRPC拦截器的使用.gRPC自身只能设置一个拦截器,所有逻辑都写一起会比较乱.本篇简单介绍go-grpc-middleware的 ...

  5. shiro:集成Spring(四)

    基于[加密及密码比对器(三)]项目改造 引入相关依赖环境 shiro-spring已经包含 shiro-core和shiro-web 所以这两个依赖可以删掉 <!--shiro继承spring依 ...

  6. C# WCF的通信模式

    wcf 通信模式一般分为三种; 1,请求/响应模式 2,单工模式 3,双工模式 一,请求/响应模式 请求/响应通信是指客户端向服务端发送消息后,服务端会向客户端发送响应.这也意味着在接收到服务的响应以 ...

  7. C# 基础知识系列- 13 常见类库介绍(二)日期时间类

    0. 前言 上一篇内容介绍了Console类和Math类,这篇内容着重介绍一下C#中时间日期的处理方式. 上一篇勘误: 上一篇中关于静态类没有构造函数,这一表述有误.正确的说法是C#中静态类不包含常规 ...

  8. EasyPoi 导入导出Excel时使用GroupName的踩坑解决过程

    一.开发功能介绍: 简单的一个excel导入功能 二.Excel导入模板(大致模板没写全): 姓名 性别 生日 客户分类 联系人姓名 联系人部门 备注 材料 综合 采购 张三 男 1994/05/25 ...

  9. thinkphp5和nginx不得不说的故事

    由于之前学习用的都是apsche,所以对ngnix一窍不通,在这里写给正在学习的同行,希望可以帮助到你们: 如果你不会用apache部署tp5的可以查看我之前发布的文章,里面有提到 phpstudy ...

  10. curl请求curl_exec返回false,curl_error返回空

    网上查找了一下,由于采用https协议,一定要加入以下两句 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书下同 curl_setopt ...