【Java学习】匿名内部类的向外访问机制
目录
一、方法局部变量的访问
1.生命周期
1.1方法生命周期
1.2匿名实例生命周期
1.3生命超时性
2.变量捕获
2.1按值捕获
2.1.1值捕获优势
2.1.1.1生命及时访问
2.1.1.2线程安全
2.1.2常量值捕获优势
2.2按引用捕获
引用捕获风险
(1)生命超时访问
(2)线程不安全
二、外部类成员变量的访问
1.生命周期
1.1非静态成员
1.2静态成员
1.3生命及时性
2.引用访问
2.1非静态匿名类的引用访问
2.2静态匿名类的引用访问
3.线程安全问题
一、方法局部变量的访问
1.生命周期
1.1方法生命周期
方法的生命周期 从方法调用开始 到 方法的最后一行执行完结束
1.2匿名实例生命周期
匿名内部类创建的 实例对象的生命周期 取决于对象的引用情况:
对象被创建后,其生命周期 就独立于 创建它们的方法,当实例对象引用 传递到其它线程或方法里 继续引用该对象时,即使创建方法的生命周期结束,销毁了它里面的 该实例对象的引用,实例对象 仍然可能在其它地方 被引用而继续存在,生命周期可以比创建方法的生命周期长
1.3生命超时性
匿名内部类 在方法里面 定义类结构,实例对象的生命周期 可能比 局部变量的生命周期长,代表着实例对象的匿名内部类 可能会生命超时地 悬空访问 方法局部变量
2.变量捕获
匿名内部类 在方法中进行 定义类结构与创建实例,在方法中定义类结构时,会将局部方法的变量 复制捕获进内部类结构中 作成员变量 进行访问
2.1按值捕获
Java的匿名内部类 捕获所在创建方法的局部变量时,只复制捕获 方法局部变量的 final常量/等效final变量的 常量值 到内部类 作为新增的副本成员保存
2.1.1值捕获优势
2.1.1.1生命及时访问
复制捕获值 入副本成员 避免了 创建方法局部变量的生命 可能更短提前销毁 而造成的悬空访问的问题
2.1.1.2线程安全
同时如果一个方法中 定义有许多线程的匿名内部类,每个内部类 将同个方法的局部变量复制到各自内部类里面的 独立副本成员中,就不会形成 并发修改 同一外部方法局部变量 而造成线程安全问题
2.1.2常量值捕获优势
复制捕获final常量值 入副本常量成员,常量在内部无法修改,避免了在内部修改副本成员变量 而外部方法局部变量实际不会改变的 可能错乱对应问题
2.2按引用捕获
C++的Lambda表达式捕获变量时,可以复制捕获 变量引用 入副本成员引用变量
引用捕获风险
(1)生命超时访问
在Lambda表达式内部 就能引用修改外部变量,要确保 实例对象的生命周期 最好不要超过 局部变量的作用域,可以通过延长局部变量生命周期 或限制Lambda不能访问已销毁的局部变量 来避免悬空引用问题
(2)线程不安全
当函数中定义多个 线程的匿名内部类时,要用同步机制 确保 多线程并发修改共同局部变量的 线程安全
二、外部类成员变量的访问
1.生命周期
1.1非静态成员
匿名内部类实例存在时,其内部就存储着 外部类的this引用,外部类就不可能被销毁,生命周期安全地 访问外部类所有成员
1.2静态成员
关于类的实例还在,类就不会被卸载,匿名内部类实例的生命周期 一定小于 外部类的生命周期,生命周期安全地 访问外部类的静态成员
1.3生命及时性
外部类成员变量的生命周期 一定比 匿名内部类实例的生命周期长,代表着实例对象的匿名内部类 一定生命及时地 安全访问 外部类的成员变量
2.引用访问
外部类成员变量的生命周期 一定比匿名内部类实例的生命周期长,所以就不使用 复制捕获变量访问,选择直接引用访问
2.1非静态匿名类的引用访问
在持有外部类实例引用的 非静态方法里面 定义匿名内部类的 类结构,内部类持有 外部类实例对的 this引用,可以访问外部类的所有成员
2.2静态匿名类的引用访问
在静态方法里面 定义匿名内部类的 类结构,内部类只能访问外部类的静态成员
3.线程安全问题
多个匿名线程 并发访问同一成员变量时 有线程安全问题