1. 从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形式参数定义处或者方法体处),因而访问方法中的局部变量(形式参数或局部变量)是天经地义的.是很自然的
  2. 为什么JAVA中要加上一条限制:只能访问final型的局部变量?
  3. JAVA语言的编译程序的设计者当然全实现:局部内部类能访问方法中的所有的局部变量(因为:从理论上这是很自然的要求),但是:编译技术是无法实现的或代价极高.
  4. 困难在何处?到底难在哪儿?
    局部变量的生命周期与局部内部类的对象的生命周期的不一致性!
  5. 设方法f被调用,从而在它的调用栈中生成了变量i,此时产生了一个局部内部类对象inner_object,它访问了该局部变量i .当方法f()运行结束后,局部变量i就已死亡了,不存在了.但:局部内部类对象inner_object还可能 一直存在(只能没有人再引用该对象时,它才会死亡),它不会随着方法f()运行结束死亡.这时:出现了一个"荒唐"结果:局部内部类对象inner_object要访问一个已不存在的局部变量i!
  6. 如何才能实现? 当变量是final时,通过将final局部变量"复制"一份,复制品直接作为局部内部中的数据成员.这样:当局部内部类访问局部变量时,其实真正访问的是这个局部变量的"复制品"(即:这个复制品就代表了那个局部变量).因此:当运行栈中的真正的局部变量死亡时,局部内部类对象仍可以访问局部变量(其实访问的是"复制品"),给人的感觉:好像是局部变量的"生命期"延长了.

那么:核心的问题是:怎么才能使得:访问"复制品"与访问真正的原始的局部变量,其语义效果是一样的呢?
当变量是final时,若是基本数据类型,由于其值不变,因而:其复制品与原始的量是一样.语义效果相同.(若:不是final,就无法保证:复制品与原始变量保持一致了,因为:在方法中改的是原始变量,而局部内部类中改的是复制品)

当变量是final时,若是引用类型,由于其引用值不变(即:永远指向同一个对象),因而:其复制品与原始的引用变量一样,永远指向同一个对象(由于是final,从而保证:只能指向这个对象,再不能指向其它对象),达到:局部内部类中访问的复制品与方法代码中访问的原始对象,永远都是同一个即:语义效果是一样的.否则:当方法中改原始变量,而局部内部类中改复制品时,就无法保证:复制品与原始变量保持一致了(因此:它们原本就应该是同一个变量.)

一句话:这个规定是一种无可奈何.也说明:程序设计语言的设计是受到实现技术的限制的.这就是一例. 因为:我就看到不少人都持这种观点:设计与想法是最重要的,实现的技术是无关紧要的,只要你作出设计与规定,都能实现.

现在我们来看,如果我要实现一个在一个方法中匿名调用ABSClass的例子:

    public static void test(final String s){ABSClass c = new ABSClass(){public void m(){int x = s.hashCode();System.out.println(x);}};//其它代码.}

从代码上看,在一个方法内部定义的内部类的方法访问外部方法内局部变量或方法参数,是非常自然的事,但内部类编译的时候如何获取这个变量,因为内部类除了它的生命周期是在方法内部,其它的方面它就是一个普通类。那么它外面的那个局部变量或方法参数怎么被内部类访问?编译器在实现时实际上是这样的:

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

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

Java代码:

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){//一旦参数在匿名类内部使用,则必须是finalABSClass 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参数的根本意义.

匿名内部类使用外面的类为什么要用final型相关推荐

  1. 【Kotlin】Kotlin 类的继承 一 ( 类继承基本方式 | final 关键字 | 子类主构造函数 | 子类次构造函数 )

    文章目录 I . 类继承基本方式 II . 使用 final 禁止类继承 / 方法重写 III . 父类没有主构造函数 IV . 父类有主构造函数 V . 父类构造函数与子类构造函数总结 I . 类继 ...

  2. 43、在java中一个类被声明为final类型,表示了什么意思?

    43.在java中一个类被声明为final类型,表示了什么意思? 表示该类不能被继承,是顶级类. JAVA面试问题及答案大全

  3. 定义一个名为Circle的类,其中含有double型的成员变量centerX 和centerY表示圆心坐标,radius表示圆的半径。

    定义一个名为Circle的类,其中含有double型的成员变量centerX 和centerY表示圆心坐标,radius表示圆的半径. 定义求圆的面积方法getArea()方法和求圆周长的方法getP ...

  4. (1)定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个 findArea()方法返回圆的面积。 (2)定义一个类PassObject,在类中定义一个方法printA

      (1)定义一个 Circle 类,包含一个 double 型的 radius 属性代表圆的半径,一个 findArea() 方法返回圆的面积. ( 2 )定义一个类 PassObject ,在类中 ...

  5. 面向对象--类、方法、final、继承、组合

    对象.类-表格 类-表格的表头 对象-表格的内容 类就是对象的抽象,对象的模板. 对象是类的具体实例. |姓名|年龄| |张三 | 14 | | 李4 | 20 | 类:class.对象:object ...

  6. java中单例设计模式登记式单例类_java23种设计模式-创建型模式之单例模式

    单例模式(Singleton) 单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.某些类创建比较频 ...

  7. MFC中CString类字符串与长整型、浮点型、字符数组char数据之间的相互转换

    一.长整型数据与CString类字符串相互转换 1.将长整型数据转换为CString字符串类 CString str; long ld; str.Format(_T("%ld"), ...

  8. 定义一个类Box,类中有三个整型,表示长,宽,高,定义setInfo(int,int,int)方法,设置三个变量的值。定义volum()方法计算体积//定义area()方法计算表面积。定义to

    toString方法:将对象转成字符串,放便打印. 在输出一个对象的时候,默认的就是调用这个对象的toString方法. 如果项目里面需要输出一个对象的时候,可以去重写toString方法. 源代码: ...

  9. (带手机版数据同步)蓝色大气隔声装饰工程公司类网站源码 营销型工程装饰网站织梦模板

    介绍 本套织梦模板采用织梦最新内核开发的模板,这款模板使用范围广,不仅仅局限于一类型的企业,营销型网站.装饰工程类的网站都可以用该模板.你只需要把图片和文章内容换成你的即可,颜色都可以修改,改完让你耳 ...

  10. java final 意思_在java中一个类被声明为final类型,表示的意思是()。

    案例分析一:假定CPU的主频是500MHz.硬盘采用DMA方式进行数据传送,其数据传输率为4MB/s, 每次DMA传输的数据量为8KB, 要求没有任何数据传输被错过. 如果CPU在DMA初始化设置和启 ...

最新文章

  1. selenium2与python自动化5-iframe和163邮箱登录
  2. “红人经济第一股”搞虚拟社交,天下秀是变道还是扩道?
  3. 低精度神经网络:从数值计算角度优化模型效率
  4. 你了解 Assembly.Load 吗?
  5. LeetCode 285. 二叉搜索树中的顺序后继(中序遍历)
  6. 【原创】OllyDBG 入门系列(一)-认识OllyDBG
  7. 【AI视野·今日CV 计算机视觉论文速览 第237期】Thu, 30 Sep 2021
  8. springcloud 入门 4 (rebbon源码解读)
  9. 继爱奇艺之后,腾讯视频、优酷宣布:取消剧集超前点播服务
  10. features its own
  11. nginx 代理springmvc到二级目录_详解Nginx从入门到实践
  12. Openwrt下ipk包的安装、卸载与更新
  13. tiptop 编译运行_TIPTOP MPS(amsp500)运行流程
  14. android自动切换输入法,一种动态切换Android系统输入法的弹出模式的方法
  15. Liferay登陆提示认证失败!
  16. 深挖数字科技与场景 详解京东数字科技三大技术能力
  17. PM,PL,SE,PG都是什么意思,职责划分
  18. Word 去除脚注分隔线前的空格
  19. 香港大学SPACE中国商业学院暨企业研究院第三届创新创业大赛全国总决赛圆满收官
  20. 新解决方案销售之一:原则与流程

热门文章

  1. android 批量扫描,Android:连续扫描所有AP(接入点)
  2. linux soc 程序崩溃,SOC、FLCK和内存之间的关系,以3900X+X570为例(更新PCIE4.0)
  3. Jmeter之app性能测试(ios,android)
  4. VMware中虚拟机Ubuntu访问Windows7主机文件夹的设置流程
  5. 深度学习笔记_基本概念_卷积网络中的通道channel、特征图feature map、过滤器filter和卷积核kernel
  6. 论文笔记_SLAM_Simultaneous Localization And Mapping: A Survey of Current Trends in Autonomous Driving
  7. node.js(三)MongoDB数据库搭建
  8. LeetCode之翻转字符串里的单词
  9. 属性变量,实例变量,全局变量
  10. logstash收集TCP端口日志