匿名内部类为什么访问外部类局部变量必须是final的?

1.内部类里面使用外部类的局部变量时,其实就是内部类的对象在使用它,内部类对象生命周期中都可能调用它,而内部类试图访问外部方法中的局部变量时,外部方法的局部变量很可能已经不存在了,那么就得延续其生命,拷贝到内部类中,而拷贝会带来不一致性,从而需要使用final声明保证一致性。说白了,内部类会自动拷贝外部变量的引用,为了避免:1. 外部方法修改引用,而导致内部类得到的引用值不一致 2.内部类修改引用,而导致外部方法的参数值在修改前和修改后不一致。于是就用 final 来让该引用不可改变。

2.内部类通常都含有回调,引用那个匿名内部类的函数执行完了就没了,所以内部类中引用外面的局部变量需要是final的,这样在回调的时候才能找到那个变量,而如果是外围类的成员变量就不需要是final的,因为内部类本身都会含有一个外围了的引用(外围类.this),所以回调的时候一定可以访问到。例如:

private Animator createAnimatorView(final View view, final int position) {
    MyAnimator animator = new MyAnimator();
    animator.addListener(new AnimatorListener() {
        @Override
        public void onAnimationEnd(Animator arg0) {
            Log.d(TAG, "position=" + position);
        }
    });
    return animator;
}

内部类回调里访问position的时候createAnimatorView()早就执行完了,position如果不是final的,回调的时候肯定就无法拿到它的值了,因为局部变量在函数执行完了以后就被回收了。

3.我们反编译看一下,首先定义接口和匿名内部类:

public interface MyInterface {
    void doSomething();
}

public class TryUsingAnonymousClass {
    public void useMyInterface() {
        final Integer number = 123;
        System.out.println(number);

        MyInterface myInterface = new MyInterface() {
            @Override
            public void doSomething() {
                System.out.println(number);
            }
        };
        myInterface.doSomething();

        System.out.println(number);
    }
}

我们进行反编译,结果是:

class TryUsingAnonymousClass$1
        implements MyInterface {
    private final TryUsingAnonymousClass this$0;
    private final Integer paramInteger;

    TryUsingAnonymousClass$1(TryUsingAnonymousClass this$0, Integer paramInteger) {
        this.this$0 = this$0;
        this.paramInteger = paramInteger;
    }

    public void doSomething() {
        System.out.println(this.paramInteger);
    }
}

可以看到名为number的局部变量是作为构造方法的参数传入匿名内部类的。

如果Java允许匿名内部类访问非final的局部变量的话,那我们就可以在TryUsingAnonymousClass$1中修改paramInteger,但是这不会对number的值有影响,因为它们是不同的reference。

这就会造成数据不同步的问题。

所以,Java为了避免数据不同步的问题,做出了匿名内部类只可以访问final的局部变量的限制。

参考:http://cuipengfei.me/blog/2013/06/22/why-does-it-have-to-be-final/

时间: 2024-11-06 13:43:53

匿名内部类为什么访问外部类局部变量必须是final的?的相关文章

深入理解Java中为什么内部类可以访问外部类的成员

内部类简介 虽然Java是一门相对比较简单的编程语言,但是对于初学者, 还是有很多东西感觉云里雾里, 理解的不是很清晰.内部类就是一个经常让初学者感到迷惑的特性. 即使现在我自认为Java学的不错了, 但是依然不是很清楚.其中一个疑惑就是为什么内部类对象可以访问外部类对象中的成员(包括成员变量和成员方法)? 早就想对内部类这个特性一探究竟了,今天终于抽出时间把它研究了一下. 内部类就是定义在一个类内部的类.定义在类内部的类有两种情况:一种是被static关键字修饰的, 叫做静态内部类, 另一种是

内部类访问外部类的变量必须是final吗,java静态方法中不能引用非静态变量,静态方法中不能创建内部类的实例

内部类访问外部类的变量必须是final吗? 如下:class A{int i = 3;public void shout(){ class B{public void shout1(){System.out.println(i);} }B b=new B();b.shout1();} public static void main(String [] args){A a=new A();a.shout();} }可正常输出3,证明可以访问类的变量i,但改为下面的方式:class A{public

JavaSE8基础 内部类可以访问外部类的私有成员

os :windows7 x64    jdk:jdk-8u131-windows-x64    ide:Eclipse Oxygen Release (4.7.0)        代码: //内部类 就是在一个类的内部在定义一个类 //外部类 class TestOuter { private int num = 10; //内部类 private class TestInner { public void showInner() { //内部类可以访问外部类的私有成员 System.out.

Java基础-内部类-为什么成员内部类可以无条件访问外部类

在此之前,我们已经讨论过了成员内部类可以无条件访问外部类的成员,那具体究竟是如何实现的呢?下面通过反编译字节码文件看看究竟.事实上,编译器在进行编译的时候,会将成员内部类单独编译成一个字节码文件,下面是Outter.java的代码: public class Outter { private Inner inner = null; public Outter() { } public Inner getInnerInstance() { if(inner == null) inner = new

java 内部类如何访问外部类的对象

用this就可以做到 实例如下: package innerclass; /** * 内部类如何得到外部类的对象 *  * */ public class DotThis { public class Inner { //返回外部内的对象 public DotThis outer(){ return DotThis.this; } } public void print(){ System.out.println("Out class"); } /** * 得到内部内的对象 */ pu

内部类练习题(外部类访问内部类成员、内部类访问外部类成员、顶级类访问内部类成员)

package com.Summer_0429.cn; /** * @author Summer * 内部类实例: * 定义一只猫类,猫有: * 1.重量 * 2.猫的身体: * 1)颜色 * 2)显示猫的身体的信息(): * 3.显示猫的整体信息(): * 要求:创建一只小猫,显示它的整体信息. * */ class Cat{ private double weight; public Cat(double weight){ this.weight = weight; } //内部类:成员内部

Android(java)学习笔记150:为什么局部内部类只能访问外部类中的 final型的常量

为什么匿名内部类参数必须为final类型: 1)  从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形式参数定义处或者方法体处),因而访问方法中的局部变量(形式参数或局部变量)是天经地义的,是很自然的. 2) 为什么JAVA中要加上一条限制:只能访问final型的局部变量? JAVA语言的编译程序的设计者当然全实现:局部内部类能访问方法中的所有的局部变量(因为:从理论上这是很自然的要求),但是:编译技术是无法实现的或代价极高. 至于为什么只能是fi

139、Java中使用this访问外部类属性

01.代码如下: package TIANPAN; class Outer { // 外部类 private String msg = "Hello World !"; class Inner { // 定义一个内部类 public void print() { System.out.println(Outer.this.msg); // 外部类.this = 外部类当前对象 } } public void fun() { Inner in = new Inner(); // 内部类对

Java:匿名内部类不能引用外部类中非final类型的变量

在使用Java局部内部类或者匿名内部类时,若该类调用了所在方法的局部变量,则该局部变量必须使用final关键字来修饰,否则将会出现编译错误“Cannot refer to a non-final variable * inside an inner class defined in a different method”. 不知道是不是因为我的编程风格问题,这个错误我经常遇到.而且我在学Java的时候不记得书上有说这个问题.所以这次拿出来百度一下. 简单百度了一下,好像没什么详细的解释,大概是牵