Java匿名内部类访问外部变量,为何需被标志为final?

对于Java语言中的final使用,大家应该很熟悉,可以修饰类,表示不可继承;可以修饰方法,表示不可被子类重写;可以修饰变量,表示不可以被二次赋值。那么,Java匿名内部类访问外部变量,为何需被标志为final?这跟上述三个特性有关系吗?

一、问题的提出

Java编程中,使用匿名内部类访问外部方法的局部变量是一件很常见的事件,比如以下代码,使用匿名内部类设置控件的监听器是再常见不过了,下面的例子中,因为匿名监听器类访问了外部局部变量name,编译器提示name变量必须使用final修饰。

  //初始化按钮的监听器
    public void initListener(Button btn ){
        final int name = "王大锤"; //必须标记为final

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                btn.setText(name); //动态改变按钮的文字
            }
        });
    }

为何name变量需被标志为final?这深层次的原因是什么?为什么有这样一个让人摸不着头脑的规定?

二、解释

  • 这要从闭包说起,匿名内部类和外部方法形成了一个闭包,因此,匿名内部类能够访问外部方法的变量,看起来是一种“天经地义”的事情,Java语言当然也需要实现这种特性,但是这里遇到了一个问题。

  • 匿名内部类的生命周期可能比外部的类要长,因此访问外部局部变量有可能是访问不到的。

  • 那怎么办呢?Java语言为了实现这种特性, 只好将外部的局部变量偷偷的赋值了一份给匿名内部类。那这样匿名内部类就可以肆无忌惮的访问外部局部变量了。

  • 问题又来了,这种通过赋值的形式有一个缺陷,匿名内部类不可以修改“原来的局部变量”,因为是一份“复制品”,修改复制品对原变量没什么影响啊。

  • 那怎么办? Java语言干脆强制要求被匿名内部类访问的外部局部变量必须是final的,什么意思呢?就是“一刀切”,不让修改了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,929评论 18 399
  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 7,579评论 0 11
  • Java 内部类 分四种:成员内部类、局部内部类、静态内部类和匿名内部类。 1、成员内部类: 即作为外部类的一个成...
    ikaroskun阅读 5,016评论 0 13
  • 记不清楚多少次像今夜这样难以入眠,手机里放的是薛之谦的刚刚好,刚刚好,我躺在了床上,刚刚好,我想写点什么. 这一切...
    Kikiiii阅读 1,566评论 0 0
  • 在一个月之前,蔺老师给我出了一道题目,据说是可以吹一年的题目,所以我当时压根就没觉得我这么蠢的人能答得出来蔺老师给...
    Originalee阅读 4,181评论 0 6