`
lluser
  • 浏览: 4072 次
  • 性别: Icon_minigender_2
  • 来自: 上海
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

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

阅读更多
一、匿名内部类为什么只能用final.
   是变量的作用域的问题,因为匿名内部类是出现在一个方法的内部的,如果它要访问这个方法的参数或者方法中定义的变量,则这些参数和变量必须被修饰为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参数的根本意义.
分享到:
评论

相关推荐

    Java中局部内部类可以访问它所在方法中定义的final修饰的局部变量的合理解释.doc

    Java中局部内部类可以访问它所在方法中定义的final修饰的局部变量的合理解释.doc

    【05-面向对象(下)】

    •局部内部类不能在外部类以外的地方使用,那么局部内部类也不能使用访问控制符和static修饰 匿名内部类 •匿名内部类适合创建那种只需要一次使用的类,定义匿名内部类的语法格式如下: •new 父类构造器...

    day022-jdk8新特性和lambda表达式 代码和笔记.rar

    1. lambda: 1. 概念:就是对函数式接口匿名内部类的简写 ... 7、lambda表达式若访问了局部变量,则局部变量必须是final的, 若是局部变量没有加final关键字,系统会自动添加,此后在修改该局部变量,会报错;

    21天学通Java-由浅入深

    240 12.2.1 创建局部内部类 240 12.2.2 在局部内部类中访问外部类成员变量 240 12.2.3 在局部内部类中访问外部类的局部变量 241 12.2.4 静态方法中的局部内部类 243 12.3 静态内部类 244 12.3.1 创建静态内部类 244 ...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    9.1.2 加餐:不可改变的final变量 211 9.1.3 多维数组的长度 212 9.1.4 一维数组的clone()方法 212 9.1.5 当数组类型不再是基本数据类型 214 9.1.6 多维数组的clone()方法 217 9.2 老朋友String类 220 9.2.1 ...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    9.1.2 加餐:不可改变的final变量 211 9.1.3 多维数组的长度 212 9.1.4 一维数组的clone()方法 212 9.1.5 当数组类型不再是基本数据类型 214 9.1.6 多维数组的clone()方法 217 9.2 老朋友String类 220 9.2.1 ...

    corejava培训文档

    7.6.1. final变量不能被改变; 7.6.2. final方法不能被改写; 7.6.3. final类不能被继承; 7.6.4. String 类 7.7. 抽象类 7.8. 接口 (模板方法模式) 7.9. Object 类 7.10. 封装类 7.11. 内部类 7.11.1. ...

    Java 基础核心总结 +经典算法大全.rar

    《Java 基础核心总结》 Java 概述 什么是 Java2 Java 的特点Java 开发环境 JDK JRE Java 开发环境配置 Java 基本语法 数据类型基础语法运算符 Java 执行控制流程条件语句 if 条件语句 if...else 条件语句if....局部变量

    疯狂JAVA讲义

    6.7.4 局部内部类 211 6.7.5 匿名内部类 212 6.7.6 闭包(Closure)和回调 215 6.8 枚举类 217 6.8.1 手动实现枚举类 217 6.8.2 枚举类入门 219 6.8.3 枚举类的属性、方法和构造器 220 6.8.4 实现接口的枚举...

    Java2实用教程.rar

    4 4 1实例变量和类变量的区别 4 4 2实例方法和类方法的区别 4 5this关键字 4 6包 4 6 1包语句 4 6 2import语句 4 6 3将类打包 4 7访问权限 4 7 1私有变量和私有方法 4 7 2共有变量和共有方法 4 7 3友好变量和友好...

    javaSE代码实例

    第6章 对象和类——Java世界的细胞 77 6.1 面向对象概述 77 6.1.1 面向对象程序设计思想的诞生 77 6.1.2 面向过程与面向对象思想的对比 78 6.1.3 面向对象技术的背景和特点 79 6.2 类的定义与对象的创建...

    java基础案例与开发详解案例源码全

    8.1.2 局部内部类206 8.1.3 静态内部类209 8.1.4 匿名内部类211 8.2 对象包装器213 8.3 装箱和拆箱216 8.4 本章习题218 第9章 9.1 String类220 9.1.1 字符串常量221 9.1.2 字符串对象操作224 9.1.3 字符串对象修改...

    java学习笔记 初学者必读

    7.6.1. final变量不能被改变; 7-22 7.6.2. final方法不能被改写; 7-23 7.6.3. final类不能被继承; 7-23 7.6.4. String 类 7-23 7.7. 抽象类 7-24 7.8. 接口 (模板方法模式) 7-25 7.9. Object 类 7-27 7.10. 封装类 7...

    corejavaNoteBook

    7.6.1. final变量不能被改变; 7-22 7.6.2. final方法不能被改写; 7-23 7.6.3. final类不能被继承; 7-23 7.6.4. String 类 7-23 7.7. 抽象类 7-24 7.8. 接口 (模板方法模式) 7-25 7.9. Object 类 7-27 7.10. 封装类 7...

    突破程序员基本功的16课.part2

    2.1.1 实例变量和类变量的属性 2.1.2 实例变量的初始化时机 2.1.3 类变量的初始化时机 2.2 父类构造器 2.2.1 隐式调用和显式调用 2.2.2 访问子类对象的实例变量 2.2.3 调用被子类重写的方法 2.3 父子实例的...

    java 面试题 总结

     final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。 finally是异常处理语句结构的一部分,表示总是执行。 finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的...

    【后端】java基础(5.4)java高级基础之java的修饰符——非访问控制符

    上章讲了访问控制符,这章开始讲非访问控制符。...√(只可修饰内部类) √ √ × final 最终的 √ √ √ √ abstract 抽象的 √ √ √ × 首先我们来说说static: 被static修饰的方法我们称为静态方

Global site tag (gtag.js) - Google Analytics