美文网首页
匿名内部类访问方法成员变量

匿名内部类访问方法成员变量

作者: 枫叶忆 | 来源:发表于2019-06-14 09:51 被阅读0次

在java编程中,没用的类定义太多对系统来说也是一个负担,这时候我们可以通过定义匿名内部类来简化编程,但匿名内部类访问外部方法的成员变量时都要求外部成员变量添加final修饰符final修饰变量代表该变量只能被初始化一次,以后不能被修改。但为什么匿名内部类访问外部成员变量就不允许他修改了呢?

接下来这个例子应该足够把这些说清楚了:

示例代码:

public class InnerFinalTest {

private static Test test0= null;

public static void main(String[] args) {

new InnerFinalTest().method1();

System.out.println("-------");

test0.test();

}

public void method1(){

final Test  test = new Test();

test0 = new Test(){

@Override

public void test(){

System.out.println("匿名内部类:" + test);

Field[] field = this.getClass().getDeclaredFields();

for (int i = 0; i < field.length; i++) {

System.out.println(field[i].getName());

}

}

};

InnerFinalTest ift = new InnerFinalTest();

ift.innerFinalTest(test0);

System.out.println("外部直接访问变量:"+ test);

}

public void innerFinalTest(Test test){

test.test();

}

}

Test类无关紧要,不过还是贴一下他吧

public class Test {

public void test(){

System.out.println("啊啊啊啊啊!" );

}

}

说明:

为什么我们要将被匿名内部类访问的变量定义成final呢?

首先,我们在InnerFinalTest类中定义了一个static变量test0:

private static Test test0= null;

该语句说明test0的生命周期和类一样

接下来在main方法中调用method1(),在method1()中将我们定义的匿名内部类赋给了test0,这说明如果test0不往别处指的话,我们匿名内部类将被一直引用着,

如同吃了九转大金丹,与天地同寿,与日月齐光,匿名内部类生命周期和InnerFinalTest类(匿名类的天地)相同了。

但是,method1()调用完了他要释放资源了,所以method1()方法中:

final Test  test = new Test();

test变量也要被释放了,test没了,但匿名内部类引用了test,如果java编译器不搞点小动作,他就没法玩儿了,因为匿名类的生命周期长,还使用着test,而外部变量先撤了,背后捅了匿名内部类一刀子。。。

匿名内部类说,就防着你这一招呢,所以叫编译器大哥帮忙搞了个小动作,明修栈道暗度陈仓,编译的时候,我自己把你给我的变量备份了一份,表面上看是我引用了你的变量,其实在运行期间我就用我自己备份的了。但是别人表面上看不知道我备份了一份,还以为我用的你的,如果不定义成final,变量在外面被修改了,我没改,那我的结果就会和预期不同,为了防止出现这种情况,所以要被定义成final。

上面实例代码运行结果:

匿名内部类:Test@40e455bf

this$0

val$test

外部直接访问变量:Test@40e455bf

-------

匿名内部类:Test@40e455bf

this$0

val$test

我用反射证明了匿名内部类存在外部变量的备份val$test,其中因为变量是默认类型,所以使用getDeclaredFields得到所有匿名内部类运行期间存在的成员属性,注意,该成员属性在编码期间是不存在的,

是编译器主动为匿名内部类添加的成员属性,所以可以通过反射在运行期间一窥究竟。

如果去掉匿名内部类对外部变量的引用,如去掉以下代码:

System.out.println("匿名内部类:" + test);

运行结果中会没有了val$test,这也再次证明了以上结论:匿名内部类备份了变量。

通过外部变量和内部变量打印内容相同,说明两个变量test和val$test的变量引用指向的内存区域是相同的,(这里可以参考一下原型模式浅克隆)。指向相同对象,虽然对象不能修改,但对象中的属性可以修改,而匿名内部类变量和外部变量指向相同,自然值也同步修改了。

总结一下,逻辑应该是这样的:为了解决生命周期不同的问题,匿名内部类备份了变量,为了解决备份变量引出的问题,外部变量要被定义成final

我们匿名内部类使用final不是怕修改,是怕不能同步修改。

原文:https://blog.csdn.net/wjw521wjw521/article/details/77333820

相关文章

  • 内部类

    内部类主要分为: 1、静态内部类 -- 不能访问外部类的非静态成员变量和方法。 2、匿名内部类 3、成...

  • Java内部类

    代码中包含成员内部类、内部类的同名变量访问、局部内部类、局部内部类final、匿名内部类

  • 匿名内部类访问方法成员变量

    在java编程中,没用的类定义太多对系统来说也是一个负担,这时候我们可以通过定义匿名内部类来简化编程,但匿名内部类...

  • 匿名内部类不能访问外部类方法中的局部变量,除非变量被声明为fin

    这里所说的“匿名内部类”主要是指在其外部类的成员方法内定义,同时完成实例化的类,若其访问该成员方法中的局部变量,局...

  • 内部类

    成员内部类 局部内部类(定义在方法内和定义在作用域内的类) 匿名内部类

  • SharedPreferences、内外部存储

    java中规定,内部类只能访问外部类中的成员变量,不能访问方法中定义的变量,如果要访问方法中的变量,就要把方法中的...

  • 匿名内部类中使用的局部变量设置为final

    匿名内部类不能访问外部类方法中的局部变量,除非变量被声明为final类型 1. 这里所说的“匿名内部类”主要是指在...

  • 非静态内部类的Handeler造成内存泄漏问题

    “非静态内部类会持有外部类的引用” ,所以非静态内部类可以访问外部类成员变量。 当我们使用匿名内部类实现Handl...

  • Java--内部类的分类-2

    【示例】内部类的访问 输出:  内部类方法里的局部变量age: 30  内部类的成员变量age: 20  外部类的...

  • 匿名内部类问题

    匿名内部类访问的外部类局部变量为什么要用final 修饰,jdk8为啥不需要了? 匿名内部类访问的外部类局部变量为...

网友评论

      本文标题:匿名内部类访问方法成员变量

      本文链接:https://www.haomeiwen.com/subject/vcxufctx.html