java基础篇 之 再探内部类跟final

简介: 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的时候这段代码明明是报错的,就像这样:

image.png

明明会提醒一定要申明为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”这个字符串,你不会发生改变,那么即使你死亡了,


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


相关文章
|
1月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
67 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
30天前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
28 3
|
28天前
|
存储 安全 Java
了解final关键字在Java并发编程领域的作用吗?
在Java并发编程中,`final`关键字不仅用于修饰变量、方法和类,还在多线程环境中确保对象状态的可见性和不变性。本文深入探讨了`final`关键字的作用,特别是其在final域重排序规则中的应用,以及如何防止对象的“部分创建”问题,确保线程安全。通过具体示例,文章详细解析了final域的写入和读取操作的重排序规则,以及这些规则在不同处理器上的实现差异。
了解final关键字在Java并发编程领域的作用吗?
|
1月前
|
Java 编译器
在Java中,关于final、static关键字与方法的重写和继承【易错点】
在Java中,关于final、static关键字与方法的重写和继承【易错点】
21 5
|
2月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
1月前
|
缓存 安全 Java
Java中 final、finally、finalize 有什么区别?
本文详细阐述了Java中`final`、`finally`和`finalize`的区别:`final`用于修饰类、方法和变量以表示不可变性;`finally`是用于确保在`try-catch`结构中无论是否发生异常都能执行的代码块;而`finalize`是`Object`类的方法,用于在对象被垃圾回收前执行清理工作,但在JDK 9中已被标记为弃用。
29 0
Java中 final、finally、finalize 有什么区别?
|
1月前
|
Java
Java关键字 —— static 与 final 详细解释!一看就懂 有代码实例运行!
这篇文章详细解释了Java中static和final关键字的用法,包括它们修饰类、方法、变量和代码块时的行为,并通过代码示例展示了它们的具体应用。
178 0
Java关键字 —— static 与 final 详细解释!一看就懂 有代码实例运行!
|
1月前
|
存储 安全 Java
了解final关键字在Java并发编程领域的作用吗?
了解final关键字在Java并发编程领域的作用吗?
|
1月前
|
Java 编译器
【Java】内部类
【Java】内部类
21 0
|
1月前
|
Java 程序员 编译器
【Java】继承、super、final、子类构造方法
【Java】继承、super、final、子类构造方法
26 0