知识大全 为什么匿名内部类参数必须为final类型
Posted 变量
篇首语:三百六十行,行行出状元。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 为什么匿名内部类参数必须为final类型相关的知识,希望对你有一定的参考价值。
在线文档阅读开发手记(一) ) 从程序设计语言的理论上 局部内部类(即 定义在方法中的内部类) 由于本身就是在方法内部(可出现在形式参数定义处或者方法体处) 因而访问方法中的局部变量(形式参数或局部变量)是天经地义的 是很自然的 ) 为什么JAVA中要加上一条限制 只能访问final型的局部变量? ) JAVA语言的编译程序的设计者当然全实现 局部内部类能访问方法中的所有的局部变量(因为 从理论上这是很自然的要求) 但是 编译技术是无法实现的或代价极高 ) 困难在何处?到底难在哪儿? 局部变量的生命周期与局部内部类的对象的生命周期的不一致性! ) 设方法f被调用 从而在它的调用栈中生成了变量i 此时产生了一个局部内部类对象inner_object 它访问了该局部变量i 当方法f()运行结束后 局部变量i就已死亡了 不存在了 但 局部内部类对象inner_object还可能 一直存在(只能没有人再引用该对象时 它才会死亡) 它不会随着方法f()运行结束死亡 这时 出现了一个 荒唐 结果 局部内部类对象inner_object要访问一个已不存在的局部变量i! ) 如何才能实现?当变量是final时 通过将final局部变量 复制 一份 复制品直接作为局部内部中的数据成员 这样 当局部内部类访问局部变量时 其实真正访问的是这个局部变量的 复制品 (即 这个复制品就代表了那个局部变量) 因此 当运行栈中的真正的局部变量死亡时 局部内部类对象仍可以访问局部变量(其实访问的是 复制品 ) 给人的感觉 好像是局部变量的 生命期 延长了 那么 核心的问题是 怎么才能使得 访问 复制品 与访问真正的原始的局部变量 其语义效果是一样的呢? 当变量是final时 若是基本数据类型 由于其值不变 因而 其复制品与原始的量是一样 语义效果相同 (若 不是final 就无法保证 复制品与原始变量保持一致了 因为 在方法中改的是原始变量 而局部内部类中改的是复制品) 当变量是final时 若是引用类型 由于其引用值不变(即 永远指向同一个对象) 因而 其复制品与原始的引用变量一样 永远指向同一个对象(由于是final 从而保证 只能指向这个对象 再不能指向其它对象) 达到 局部内部类中访问的复制品与方法代码中访问的原始对象 永远都是同一个即 语义效果是一样的 否则 当方法中改原始变量 而局部内部类中改复制品时 就无法保证 复制品与原始变量保持一致了(因此 它们原本就应该是同一个变量 ) 一句话 这个规定是一种无可奈何 也说明 程序设计语言的设计是受到实现技术的限制的 这就是一例 因为 我就看到不少人都持这种观点 设计与想法是最重要的 实现的技术是无关紧要的 只要你作出设计与规定 都能实现 现在我们来看 如果我要实现一个在一个方法中匿名调用ABSClass的例子 public static void test(final String s) //或final String s = axman ; ABSClass c = new ABSClass() public void m() int x = s hashCode() System out println(x) ; //其它代码 从代码上看 在一个方法内部定义的内部类的方法访问外部方法内局部变量或方法参数 是非常自然的事 但内部类编译的时候如何获取这个变量 因为内部类除了它的生命周期是在方法内部 其它的方面它就是一个普通类 那么它外面的那个局部变量或方法参数怎么被内部类访问?编译器在实现时实际上是这样的 public static void test(final String s) //或final String s = axman ; class OuterClass$ extends ABSClass private final String s; public OuterClass$ (String s) this s = s; public void m() int x = s hashCode() System out println(x) ; ABSClass c = new OuterClass$ (s) //其它代码 即外部类的变量被作为构造方法的参数传给了内部类的私有成员 假如没有final 那么 public static void test(String s) //或String s = axman ; ABSClass c = new ABSClass() public void m() s = other ; ; System out println(s) 就会编译成 public static void test(String s) //或String s = axman ; class OuterClass$ extends ABSClass private String s; public OuterClass$ (String s) this s = s; public void m() s = other ; ; ABSClass c = new OuterClass$ (s) 内部类的s重新指向 other 并不影响test的参数或外部定义的那个s 同理如果外部的s重新赋值内部类的s也不会跟着改变 而你看到的 public static void test(String s) //或String s = axman ; ABSClass c = new ABSClass() public void m() s = other ; ; System out println(s) 在语法上是一个s 在内部类中被改变了 但结果打印的出来的你认为是同一的s却还是原来的 axman 你能接收这样的结果吗? 所以final从语法上约束了实际上两个不同变量的一致性(表现为同一变量) cha138/Article/program/Java/hx/201311/26301相关参考
JAVA中使用内部类与匿名内部类实现 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! JAVA中对
publicinterfaceContents intvalue(); publicinterfaceDestination StringreadLabel(); publiccl
本文代码展示了在一个方法中通过匿名内部类定义一个Thread并Override它的run()方法之后直接启动该线程 下面的代码展示了在一个方法中通过匿名内部类定义一个Thread并Overrid
Java通过对Java语言规范进行修改显著简化了一些实用结构的实现在那些修改中最引人注目的就是内部类和匿名类如运用得当它们可使程序更易理解和维护本文介绍内部类和匿名
一用var定义变量 在C#中提供了一种新的声明变量的方式这就是var通过这个关键字在声明变量时就无需指定类型了变量类型是在初始化时由编译器确定的代码如下:varss=abcd;MessageBo
通过合成方法创建新类时永远不必担心对那个类的成员对象的收尾工作每个成员都是一个独立的对象所以会得到正常的垃圾收集以及收尾处理——无论它是不是不自己某个类一个成员但在进行初始化的时候必须覆蓋衍生类中
由于每个类都会生成一个class文件用于容纳与如何创建这个类型的对象有关的所有信息(这种信息产生了一个名为Class对象的元类)所以大家或许会猜到内部类也必须生成相应的class文件用来容纳与它们
Final关键字对JVM类加载器的影响 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &
C#中的匿名类型与隐式类型变量 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在C#中引入了Li
了解C#特性匿名类型与隐式类型局部变量 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &