java基础篇 之 再探内部类跟final
之前写过一篇文章:从垃圾回收机制解析为什么局部内部类只能访问final修饰的局部变量以及为什么加final能解决问题,经过这两天的学习,发现有些不对,必须再来捋一捋
先看之前的例子:
/**
* @author dmz
* @date Create in 22:28 2019/5/19
*/
public class Test {
public void test() {
String i = "10";
A a = new A() {
@Override
public void test() {
System.out.println(i);
}
};
}
}
interface A {
void test();
}
之前我还在Eclipse的时候这段代码明明是报错的,就像这样:

明明会提醒一定要申明为final,不知道为什么到了idea上就不会了
不过这都不是很重要,不影响我们今天的分析。
我们今天直接编译下上面的java文件:
javac Test.java
javac编译一下,得到下面两个文件,我都直接用idea打开了:
// 内部类字节码文件
class Test$1 implements A {
Test$1(Test var1, String var2) {
this.this$0 = var1;
this.val$i = var2;
}
public void test() {
System.out.println(this.val$i);
}
}
// 从上面我们可以看到,内部类对象默认持有外部类对象的引用
// 并且还持有外部类定义的变量的引用或者说是值
// 外部类字节码文件
public class Test {
public Test() {
}
public void test() {
// 可以看到在编译的时候,默认加上了final关键字
final String var1 = "10";
A var10000 = new A() {
public void test() {
System.out.println(var1);
}
};
}
}
那么现在问题来了,为什么编译的时候,默认会加上final呢?
这样有什么必要吗?
我们知道final主要作用就是:
- 对于基本数据类型,保证值不可变
- 对于引用数据类型,保证引用不可变
那么现在问题就变成了,为什么局部内部类中引用的外部数据必须要”不可变“呢?
其实这也是一种折衷的实现,究其原因还是因为局部内部类的生命周期跟方法中定义的数据生命周期不一致导致的,这点我在之前的文章里也说过了。
那么为什么加final能解决生命周期不一致的问题呢?
这就要看看我们之前编译后的class文件了,局部内部类其实是复制了一份方法内的数据的引用到自身的属性上。
如果这个引用是final的话,就代表了它不可变,那么局部内部类在复制的过程中,风险是否就缩小了呢?
比如,虽然我跟你生命周期不一样,但是我知道你一定是“10”这个字符串,你不会发生改变,那么即使你死亡了,
那么即使你这个引用死亡了,也并不影响我。大家说,是不是这么个道理呢?
java基础篇 之 再探内部类跟final的更多相关文章
- Java基础篇(JVM)——字节码详解
这是Java基础篇(JVM)的第一篇文章,本来想先说说Java类加载机制的,后来想想,JVM的作用是加载编译器编译好的字节码,并解释成机器码,那么首先应该了解字节码,然后再谈加载字节码的类加载机制似乎 ...
- 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇
Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...
- java基础篇---I/O技术(三)
接上一篇java基础篇---I/O技术(二) Java对象的序列化和反序列化 什么叫对象的序列化和反序列化 要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象 ...
- Java基础篇 - 强引用、弱引用、软引用和虚引用
Java基础篇 - 强引用.弱引用.软引用和虚引用 原创零壹技术栈 最后发布于2018-09-09 08:58:21 阅读数 4936 收藏展开前言Java执行GC判断对象是否存活有两种方式其中一种是 ...
- 小白—职场之Java基础篇
java基础篇 java基础 目录 1.java是一种什么语言,jdk,jre,jvm三者的区别 2.java 1.5之后的三大版本 3.java跨平台及其原理 4.java 语言的特点 5.什么是字 ...
- java基础篇1
JAVA基础篇1 注释 单行注释 //这是一个单行注释,由两个斜杠组成,不能嵌套多行注释 多行注释 /*这是一个 多行注释 ,//里面不能嵌套多行注释, 但是可以嵌套单行注释*/ 文档注释 /**ja ...
- Java基础篇(JVM)——类加载机制
这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...
- java基础篇---I/O技术
java基础篇---I/O技术 对于任何程序设计语言而言,输入输出(I/O)系统都是比较复杂的而且还是比较核心的.在java.io.包中提供了相关的API. java中流的概念划分 流的方向: 输 ...
- java基础篇---HTTP协议
java基础篇---HTTP协议 HTTP协议一直是自己的薄弱点,也没抽太多时间去看这方面的内容,今天兴致来了就在网上搜了下关于http协议,发现有园友写了一篇非常好的博文,博文地址:(http: ...
随机推荐
- docker 概览 (1)
Docker Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化.容器是完全使 ...
- Linux学习笔记(八)权限管理命令
权限管理命令 权限位含义 chmod chown chgrp umask默认权限 权限位含义 第1位代表文件类型 "-":普通文件 "b":块设备文件 &quo ...
- 2020-MRCTF
ez_bypass I put something in F12 for you include 'flag.php'; $flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx} ...
- jmeter事务控制器
jmeter事务控制器常用于压力测试时如果一个功能包括多个请求时,需要测试这个功能的压力情况,则需要把多个请求放到一个事务控制器里面
- Laravel - 上手实现 - 文件上传、保存到 public 目录下
1.为了访问方便,将上传的文件保存在 public 目录下,需要进行修改配置. 找到 config/filesystems.php 文件然后修改 root.具体如下: 'local' => [ ...
- C#获取文件夹内文件包括子文件(递归)实例
这个在我工作上,写了一次工具项目,用上的. static ArrayList FileList = new ArrayList();//这个必须写在方法外, static ArrayList GetA ...
- 深入理解TCP建立和关闭连接
建立连接: 理解:窗口和滑动窗口TCP的流量控制TCP使用窗口机制进行流量控制什么是窗口?连接建立时,各端分配一块缓冲区用来存储接收的数据,并将缓冲区的尺寸发送给另一端 接收方发送的确认信息中包含了自 ...
- POJ2044 天气预报---状态细则
墙角数枝梅,凌寒独自开. 遥知不是雪,为有暗香来.--王安石 题目:天气预报 网址:http://poj.org/problem?id=2044 你是一个可以控制降雨的神仙. 你是一个仁慈的神,希望土 ...
- Linux Centos7(Mac)安装Docker
docker 强调隔离性 docker:官网 docker:镜像官网: 镜像官网可以所有应用,选择安装环境:会给出安装命令,例如:docker pull redis 默认拉取最新的版本( ...
- material UI中withStyles和makeStyles的区别
在material UI中,withStyles和makeStyles是经常使用的两个用于封装样式的函数.对于刚使用material UI的开发者而言,可能不太清楚这两者的区别. 本文简要探究 ...