是变量的作用域的问题,因为匿名内部类是出现在一个方法的内部的,如果它要访问这个方法的参数或者方法中定义的变量,则这些参数和变量必须被修饰为final。因为虽然匿名内部类在方法的内部,但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或参数的作用域只在这个方法内部有效。因为编译的时候内部类和方法在同一级别上,所以方法中的变量或参数只有为final,内部类才可以引用。

Java代码: 
package com.cxz.j2se;   
  
public class MyClass {   
    public MyClass() {   
        final int finalValue = 10;   
        int not$Final = 20;   
        MyInterface myInterface = new MyInterface() {   
            public void functionWithoutPara() {   
                //compile Error   
                //System.out.println(noFinal);    
                System.out.println(finalValue);   
            }   
  
            public void functionWithPara(int num) {   
                System.out.println("The parameter " + num   
                        + " has been passed by the method");   
            }   
  
        };   
        myInterface.functionWithoutPara();   
        myInterface.functionWithPara(not$Final);   
        System.out.println(myInterface.getClass().getName());   
    }   
  
    public static void main(String[] args) {   
        new MyClass();   
  
    }   
  
}

二、为什么局部内部类只能访问final变量
  简单的来说是作用域的问题。就好像方法外面做的事情并不能改变方法内才定义的变量,因为你并不知道方法里面这个时候已经存在了这个局部变量了没有。在这个内部类中方法里面的本地变量是失效的,也就是不在作用域内,所以是不能够访问的

  但是为什么这里用final却又可以访问呢? 
  因为Java采用了一种copy   local   variable的方式来实现,也就是说把定义为final的局部变量拷贝过来用,而引用的也可以拿过来用,只是不能重新赋值。从而造成了可以access   local   variable的假象,而这个时候由于不能重新赋值,所以一般不会造成不可预料的事情发生

三、如果定义一个局部内部类,并且局部内部类使用了一个在其外部定义的对象,为什么编译器会要求其参数引用是final呢?
注意:局部内部类,包括匿名内部类。

原因如下:

abstract class ABSClass{
  public abstract void print();
}

public class Test2{
  public static void test(final String s){//一旦参数在匿名类内部使用,则必须是final
    ABSClass c=new ABSClass(){
      public void print(){
        System.out.println(s);
      }
    };
    c.print();
  }
  public static void main(String[] args){
    test("Hello World!");
  }
}

  JVM中每个进程都会有多个根,每个static变量,方法参数,局部变量,当然这都是指引用类型.基础类型是不能作为根的,根其实就是一个存储地址.垃圾回收器在工作时先从根开始遍历它引用的对象并标记它们,如此递归到最末梢,所有根都遍历后,没有被标记到的对象说明没有被引用,那么就是可以被回收的对象(有些对象有finalized方法,虽然没有引用,但JVM中有一个专门的队列引用它们直到finalized方法被执行后才从该队列中移除成为真正没有引用的对象,可以回收,这个与本主题讨论的无关,包括代的划分等以后再说明).这看起来很好.

  但是在内部类的回调方法中,s既不可能是静态变量,也不是方法中的临时变量,也不是方法参数,它不可能作为根,在内部类中也没有变量引用它,它的根在内部类外部的那个方法中,如果这时外面变量s重指向其它对象,则回调方法中的这个对象s就失去了引用,可能被回收,而由于内部类回调方法大多数在其它线程中执行,可能还要在回收后还会继续访问它.这将是什么结果?

  而使用final修饰符不仅会保持对象的引用不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期.所以这才是final变量和final参数的根本意义.

  文章出处:http://blog.csdn.net/onisland/article/details/5807637

为什么匿名内部类只能访问final变量【转】的更多相关文章

  1. Java 匿名内部类 只能访问final变量的原因

    文章来源:http://blog.sina.com.cn/s/blog_4b6f8d150100qni2.html 1)从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方 ...

  2. 匿名内部类和局部内部类只能访问final变量的原因

    以下是从各大网站找来的解释,我在这里摘抄一些从其他地方搬过来的大致思想,可能会比较乱, 详细解释 http://blog.csdn.net/salahg/article/details/7529091 ...

  3. 为什么匿名内部类和局部内部类只能访问final变量

    因为虽然匿名内部类在方法的内部,但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或 ...

  4. 为什么局部内部类和匿名内部类只能访问 final 的局部变量?

    首先,我们看一个局部内部类的例子: class OutClass { private int age = 12; public void outPrint(final int x) { class I ...

  5. 局部内部类为什么只能访问final局部变量,对于成员变量却可以随便访问?

    局部内部类为什么只能访问final局部变量,对于成员变量却可以随便访问? public class OuterClass { private int memberField = 10; public ...

  6. Java学习笔记23---内部类之局部内部类只能访问final的局部变量

    局部内部类是定义在方法体或代码块中的类,在笔记19中已有过简单介绍. 今天要讨论的是局部内部类为什么只能访问为常量的局部变量. 作者: 博客园--蝉蝉 请尊重作者劳动成果,转载请在标题注明“转载”字样 ...

  7. Java基础-内部类-为什么局部和匿名内部类只能访问局部final变量

    先看下面这段代码: public class Test { public static void main(String[] args) { } public void test(final int ...

  8. 匿名内部类中使用的外部局部变量为什么只能是final变量

    被匿名内部类引用的变量会被拷贝一份到内部类的环境中 但其后,在外部,该变量如果被修改,则内部外部不一致 Java为了避免数据不同步的问题,做出了匿名内部类只可以访问final的局部变量的限制. 究其原 ...

  9. 为什么匿名内部类只能访问其所在方法中的final类型的局部变量?

    大部分时候,类被定义成一个独立的程序单元.在某些情况下,也会把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类,包含内部类的类也被称为外部类. class Outer { priv ...

随机推荐

  1. C#连接Sql Serve数据库及增,删,改操作

    一:连接. string sqlconn = "server=主机名;database=数据名;integrated security=true" //integrated sec ...

  2. test3

    下面写几个示例:这是行内公式: \( e^{\pi i} + 1 = 0\) ,下面的是行间公式: \[ e^{\pi i} + 1 = 0. \] 另一个复杂的公式: $$J_\alpha (x) ...

  3. VMware中linux硬盘空间不足的解决方法

    相信很多人都和我一样是利用虚拟机安装linux的,在玩转linux的时候,可能就会遇到系统提示磁盘空间不足的情况.由于VMware中当初装系统时的设置的最大磁盘容量是不可以动态修改的,所以为我们使用带 ...

  4. NLua - 基于Lua的C#脚本引擎

    Nlua NLua is the bind between Lua world and the .NET world. NLua is a fork of project LuaInterface ( ...

  5. 如何将红色区域数据调用解密函数直接打印到输出控制台(例如:crt控制台)

    int main(int argc, char *argv[]) { unsigned char data[PACKET_MAX_LEN]; int data_len = 0; int socket_ ...

  6. less预处理的好处,补充关于之前发表的rem单位的运用于计算

    我认识的less 优点:优雅,好用,简单,可复用性强, 缺点:less并其实不能为我们减少沉余css代码,还是要靠自己的CSS基础去判断哪些是沉余代码或者是可以合并的代码 之前发表的一篇文章一看就懂得 ...

  7. Quickly place a window to another screen using only the keyboard

    http://askubuntu.com/questions/22207/quickly-place-a-window-to-another-screen-using-only-the-keyboar ...

  8. Citrix Reciver提示安装程序集错误

    打开注册表查找是否有RegistrySizeLimit这个项目,如果有更改成8个f,如果没有就需要手动建立一个之后输入8个f,操作方法如下: 到了 HKEY_LOCAL_MACHINE\SYSTEM\ ...

  9. linux 如何显示一个文件的某几行(中间几行)

    linux 如何显示一个文件的某几行(中间几行) [一]从第3000行开始,显示1000行.即显示3000~3999行 cat filename | tail -n +3000 | head -n 1 ...

  10. Coursera Machine Learning : Regression 评估性能

    评估性能 评估损失 1.Training Error 首先要通过数据来训练模型,选取数据中的一部分作为训练数据. 损失函数可以使用绝对值误差或者平方误差等方法来计算,这里使用平方误差的方法,即: (y ...