之前写过一篇文章:从垃圾回收机制解析为什么局部内部类只能访问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主要作用就是:

  1. 对于基本数据类型,保证值不可变
  2. 对于引用数据类型,保证引用不可变

那么现在问题就变成了,为什么局部内部类中引用的外部数据必须要”不可变“呢?

其实这也是一种折衷的实现,究其原因还是因为局部内部类的生命周期跟方法中定义的数据生命周期不一致导致的,这点我在之前的文章里也说过了。

那么为什么加final能解决生命周期不一致的问题呢?

这就要看看我们之前编译后的class文件了,局部内部类其实是复制了一份方法内的数据的引用到自身的属性上。

如果这个引用是final的话,就代表了它不可变,那么局部内部类在复制的过程中,风险是否就缩小了呢?

比如,虽然我跟你生命周期不一样,但是我知道你一定是“10”这个字符串,你不会发生改变,那么即使你死亡了,

那么即使你这个引用死亡了,也并不影响我。大家说,是不是这么个道理呢?

java基础篇 之 再探内部类跟final的更多相关文章

  1. Java基础篇(JVM)——字节码详解

    这是Java基础篇(JVM)的第一篇文章,本来想先说说Java类加载机制的,后来想想,JVM的作用是加载编译器编译好的字节码,并解释成机器码,那么首先应该了解字节码,然后再谈加载字节码的类加载机制似乎 ...

  2. 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇

    Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...

  3. java基础篇---I/O技术(三)

    接上一篇java基础篇---I/O技术(二) Java对象的序列化和反序列化 什么叫对象的序列化和反序列化 要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象 ...

  4. Java基础篇 - 强引用、弱引用、软引用和虚引用

    Java基础篇 - 强引用.弱引用.软引用和虚引用 原创零壹技术栈 最后发布于2018-09-09 08:58:21 阅读数 4936 收藏展开前言Java执行GC判断对象是否存活有两种方式其中一种是 ...

  5. 小白—职场之Java基础篇

    java基础篇 java基础 目录 1.java是一种什么语言,jdk,jre,jvm三者的区别 2.java 1.5之后的三大版本 3.java跨平台及其原理 4.java 语言的特点 5.什么是字 ...

  6. java基础篇1

    JAVA基础篇1 注释 单行注释 //这是一个单行注释,由两个斜杠组成,不能嵌套多行注释 多行注释 /*这是一个 多行注释 ,//里面不能嵌套多行注释, 但是可以嵌套单行注释*/ 文档注释 /**ja ...

  7. Java基础篇(JVM)——类加载机制

    这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...

  8. java基础篇---I/O技术

    java基础篇---I/O技术   对于任何程序设计语言而言,输入输出(I/O)系统都是比较复杂的而且还是比较核心的.在java.io.包中提供了相关的API. java中流的概念划分 流的方向: 输 ...

  9. java基础篇---HTTP协议

    java基础篇---HTTP协议   HTTP协议一直是自己的薄弱点,也没抽太多时间去看这方面的内容,今天兴致来了就在网上搜了下关于http协议,发现有园友写了一篇非常好的博文,博文地址:(http: ...

随机推荐

  1. animation-play-state 在 ios 中不生效的解决办法(JS篇)

    我们要实现动画的播放和暂停,animation-play-state 在安卓端可以使用,但是在 ios 中不起作用,这时可以使用 js 来实现相同效果. 原理 通过 js 获取当前元素的 transf ...

  2. Salesforce 学习 | 官方总结最实用的Spring '20新功能

    在Spring '20正式发布之前,Trailblazers 社区举行了一个名为Treasure Hunt的在线活动,通过预览沙盒,分享他们认为Spring ‘20中最重要的功能.这篇文章就来盘点一下 ...

  3. 浏览器中 JS 的事件循环机制

    目录 事件循环机制 宏任务与微任务 实例分析 参考 1.事件循环机制 浏览器执行JS代码大致可以分为三个步骤,而这三个步骤的往复构成了JS的事件循环机制(如图). 第一步:主线程(JS引擎线程)中执行 ...

  4. 今天开始让我们一起来学JavaScript吧!(今天先扯先别的)

    1.为什么要学习JavaScript? 首先它是web开发人员必须学习的3门语言之一: ①HTML定义了网页的内容 ②CSS描述了网页的布局: ③JavaScript网页的行为 首先JavaScrip ...

  5. 小小小小小flag

    2020:300道题 小小小小小flag 150红题 100道橙题 50道黄题 努力变强!加油 我的主页: 主页https://www.luogu.com.cn/user/306734 谢谢大家,目前 ...

  6. C#开发BIMFACE系列39 网页集成开发3:审图系统中三维模型比对

    系列目录     [已更新最新开发文章,点击查看详细] 在建筑施工图审查系统中,设计单位提交设计完成的模型/图纸,审查专家审查模型/图纸.审查过程中如果发现不符合规范的地方,则流程退回到设计单位,设计 ...

  7. 不停机还能替换代码?6年的 Java程序员表示不可思议

    相信很多人都有这样一种感受,自己写的代码在开发.测试环境跑的稳得一笔,可一到线上就抽风,不是缺这个就是少那个反正就是一顿报错,而线上调试代码又很麻烦,让人头疼得很.不过, 阿里巴巴出了一款名叫Arth ...

  8. php--static用法

    static关键字声明一个属性或方法是和类相关的,而不是和类的某个特定的实例相关,因此,这类属性或方法也称为“类属性”或“类方法”. 如果访问控制权限允许,可不必创建该类对象而直接使用类名加两个冒号“ ...

  9. ajax---post跨域思路

    ajax跨域需要加的代码 header("Access-Control-Allow-Methods:GET,POST");

  10. Dockerfle创建镜像

    简介 Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行. 一般的,Dockerfile 分为四部分:基础镜像信息.维护者信息.镜像操作指令和容器启动时执行指令. # This ...