final 是保护 所修饰的类、方法、变量不能被改变的,并不占用内存。

  真正的原因是因为生命周期的原因。方法中的局部变量,方法结束后这个变量就要释放掉,而final会保证这个变量始终指向一个对象。

java会将这个变量复制一份作为成员变量内置于内部类中(反编译class文件中可以看到),这样的话,由于final所修饰的值始终无法改变,所以这个变量所指向的内存区域就不会变。

局部内部类是嵌套在方法和作用域内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

而匿名内部类也可以说是局部内部类的一种,有时候一个类只使用一次,就可以用匿名内部类,告诉GC只用一次就可以回收了,同时也可以简化代码和方便地定义回调

需要注意的是局部内部类和匿名内部类引用外部变量时,外部的变量需要是final 的:

abstract class InnerClass {
public abstract void print();
}
public class Outer {
public  void test1(final String s1) {// 参数必须是final
    //成员内部类
    InnerClass c = new InnerClass() {
        public void print() {
            System.out.println(s1);
        }
    };
    c.print();
}

public  void test2(final String s2) {// 参数必须是final
    //匿名内部类
     new Outer() { //名字可以跟外部类一样
        public void print() {
            System.out.println(s2);
        }
    }.print();
}    
public static void main(String[] args) {
    Outer o=new Outer();
    o.test1("inner1");
    o.test2("inner2");

}
}

为什么匿名内部类和局部内部类引用外部的变量必要是final的呢?
直接看编译出来的源码吧

InnerClass:

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

Outer.class:

`import java.io.PrintStream;

public class Outer
{
  public void test1(String paramString)
  {
Outer.1 local1 = new InnerClass(this, paramString) {
  public void print() {
    System.out.println(this.val$s1);//引用了s1变量
  }

};
local1.print(); }

  public void test2(String paramString) {
new Outer(this, paramString) {//名字可以一样
  public void print() {
    System.out.println(this.val$s2);
  }
}
.print();
  }

 public static void main(String[] paramArrayOfString)
  {
Outer localOuter = new Outer();
localOuter.test1("inner1");
localOuter.test2("inner2");
  }
}

局部内部类Outer$1.class:

import java.io.PrintStream;
class 1 extends InnerClass
{
  public void print()
  {
    System.out.println(this.val$s1);//引用了s1变量
  }
}

匿名内部类Outer$2.class:

import java.io.PrintStream;
class 2 extends Outer
{
  public void print()
  {
    System.out.println(this.val$s2);//引用了s2变量
  }
}

看源码两个内部类各编译出了一个独立的class文件,也就是说Outer$1和Outer$2的生命周期是对象级别的,而变量s1、s2是方法级别的,方法运行完了变量就销毁了,而局部内部类对象Outer$1和Outer$2还可能一直存在(只能没有人再引用该对象时,它才会被GC回收),它不会随着方法运行结束就马上死亡。这时可能会出现了一种"荒唐"的结果:局部内部类对象inner_object要访问一个已不存在的局部变量s1、s2!