`
discalced
  • 浏览: 757 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

为什么localscope的内部类只能访问scope内的final参数

 
阅读更多
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){
     //或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$1 extends ABSClass{

   private final String s;
   public OuterClass$1(String s){
      this.s = s;  
   }
   public void m(){
      int x = s.hashCode();
      System.out.println(x);
   }
  };
  ABSClass c = new OuterClass$1(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$1 extends ABSClass{

   private String s;
   public OuterClass$1(String s){
      this.s = s;  
   }
   public void m(){
     s = "other";

   }
  };

   ABSClass c = new OuterClass$1 (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从语法上约束了实际上两个不同变量的一致性(表现为同一变量).
以上转自:
http://www.cnblogs.com/leier/archive/2012/03/30/2424841.html

Local classes can most definitely reference instance variables. The reason they cannot reference non final local variables is because the local class instance can remain in memory after the method returns. When the method returns the local variables go out of scope, so a copy of them is needed. If the variables weren’t final then the copy of the variable in the method could change, while the copy in the local class didn’t, so they’d be out of synch.

Anonymous inner classes require final variables because of the way they are implemented in Java. An anonymous inner class (AIC) uses local variables by creating a private instance field which holds a copy of the value of the local variable. The inner class isn’t actually using the local variable, but a copy. It should be fairly obvious at this point that a “Bad Thing”™ can happen if either the original value or the copied value changes; there will be some unexpected data synchronization problems. In order to prevent this kind of problem, Java requires you to mark local variables that will be used by the AIC as final (i.e., unchangeable). This guarantees that the inner class’ copies of local variables will always match the actual values.

以上转自:
http://aniscartujo.com/webproxy/default.aspx?prx=http://geekexplains.blogspot.com/2008/06/why-inner-classes-can-access-only-local.html


Why inner classes can access only local final variables?

Local Inner Classes and Anonymous Inner Classes can access the local final variables of the block of code they have been defined into. This block of code is typically a method.

The reason why the access has been restricted only to the local final variables is that if all the local variables would be made accessible then they would first required to be copied to a separate section where inner classes can have access to them and maintaining multiple copies of mutable local variables may lead to inconsistent data. Whereas final variables are immutable and hence any number of copies to them will not have any impact on the consistency of data.

Note: All the inner classes will continue to have access to all the members of the enclosing class. No inner class instance can exist without the corresponding enclosing class instance.

以上转自:
http://geekexplains.blogspot.com/2008/06/why-inner-classes-can-access-only-local.html
分享到:
评论

相关推荐

    java代码-Scope

    - 在同一包内的所有类可以访问此类或接口,但在不同包的类则不能。 5. **全局作用域(File Scope)**: - 在Java中,全局作用域主要指的是类或接口的顶级,即不处于任何类或方法内部的部分。 - 类、接口和导入...

    powermock maven respo

    - final类和方法:final类和方法不能被继承或重写,PowerMock可以模拟它们的行为。 - 私有方法:通常私有方法不直接暴露给测试,但有时我们需要测试它们的行为。PowerMock可以做到这一点。 - 静态初始化块:这些...

    Springboot实现mybatis多数据源配置

    public static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal(); public static void setDataSource(String dataSource) { THREAD_LOCAL.set(dataSource); } public static String get...

    java webservice axis2简单开发实例.docx

    - **服务定义**:定义了一个名为`HelloService`的服务,指定了实现类、方法等信息。 1. **部署与测试** 最后一步是将项目部署到服务器上,并进行测试。可以使用浏览器访问如下地址来获取服务的WSDL文件: ``` ...

    ssh(structs,spring,hibernate)框架中的上传下载

     使用BlobByteArrayType字段类型后,为什么我们就可以象一般的字段类型一样操作Blob字段呢?可以确定的一点是:BlobByteArrayType不可能逾越Blob天生的操作方式,原来是BlobByteArrayType数据类型本身具体数据访问...

    如何把springboot jar项目 改为war项目

    为什么需要将 Spring Boot 项目从 JAR 转换为 WAR? 在实际开发中,我们可能需要将 Spring Boot 项目部署到外部服务器上,而外部服务器可能不支持 JAR 文件的部署。例如,Tomcat 服务器默认情况下不支持 JAR 文件的...

    Biostatistics by Example Using SAS Studio

    A final chapter is devoted to sample size and power calculations. This topic is not usually covered in a book of this type, even though it is a very important topic. After reading this book, you will ...

    Cisco Press - OSPF Network Design Solutions, 2nd Edition

    Type 10: Opaque LSA: Area-Local Scope 113 Type 11: Opaque LSA: Autonomous System Scope 113 LSA Operation Example 113 Link-State Database Synchronization 116 Speaking OSPF 121 Types of OSPF Packets 121...

    Problem Solving with C++ (7th edition)

    - **Walkthrough of Functions and Local Variables**: Explanation of how functions interact with local variables, including parameter passing and scope. - **Return Types and Values**: Discussion of ...

    The Art of Assembly Language Programming

    An Easy Way to Remember the 8086 Memory Addressing Modes 4.6.2.8 - Some Final Comments About 8086 Addressing Modes 4.6.3 - 80386 Register Addressing Modes 4.6.4 - 80386 Memory Addressing ...

    100个英语常用的字根与单词组合.doc

    英语单词:finish、final 解释:fin-来自拉丁语的“finis”,意思是“结束”、“终”。在英语单词中,fin-表示结束、终等意思。 26. flect-:表示弯曲 英语单词:flection、flexible 解释:flect-来自拉丁语的...

    Java邮件开发Fundamentals of the JavaMail API

    Fundamentals of the JavaMail API Presented by developerWorks, your source for great tutorials ... Table of Contents If you're viewing this document online, you can click any of the topics below ...

Global site tag (gtag.js) - Google Analytics