`
xiebh
  • 浏览: 616036 次
  • 性别: Icon_minigender_1
  • 来自: 太原
社区版块
存档分类
最新评论

再说final变量(转)

阅读更多
转载:http://blog.csdn.net/axman/archive/2006/12/25/1460544.aspx#739121
从jdk1.0到今天,JAVA技术经过十余年的发展,技术上已经发生了巨大的变化.但final变量的定义从它
诞生那天起,就没有发生任何变化,也就是这十多年它就一直表示它原来的意思.

但遗憾的是,经过十多年仍然有90%的人没有理解它的真实含义,也没有一篇文章,包括我所见到的所有介绍
JAVA的书籍(包括TKJ)都没有说清楚,我相信肯定有些作者是理解的,但没有一个作者向读者说清楚.而中国网友
大多数人被一篇胡说八道的<<浅谈Java中final,finalized,finally>>的文章跑过马.(脸红一下:当初我也是).

final变量的定义本身并不复杂,就是变量一经初始化就不能再指向其它对象.在c++中它是一个const指针,而
不是指向const变量的指针,const指针的意思是说它只能一直指向初始化时的那个地址.但那个地址中对象本身
是可以修改的.而指向const变量的指针是说所指对象本身是不能修改的.

如:final StringBuffer sb = new StringBuffer("Axman");
sb = new StringBuffer("Sager");//错误,sb不能再指向其它对象.
sb.append(" was changed!"); //sb指向的地象本身可以修改.

先说final变量初始化:

很多文章都这么说:其初始化可以在两个地方,一是其定义处,二是在构造函数中,两者只能选其一。
胡说八道!
final变量可以在任何可以被始化的地方被始化,但只能被初始化一次.一旦被初始化后就不能再次赋
值(重新指向其它对象),作为成员变量一定要显式初始化,而作为临时变量则可以只定义不初始化(当然也不能引用)
即使是作为一个类中的成员变量,也还可以在初始化块中初始化,所以"其初始化可以在两个地方,一是其定义处,
二是在构造函数中,两者只能选其一"是错误的.


作为成员变量时,final字段可以设计不变类,是不变类的一个必要条件但不是一个充要条件.至少可以保证字段不
会以setXXX()这样的方式来改变.但无法保证字段本身不被修改(除非字段本身也是不变类);

对于方法参数的final变量:
对于方法参数的变量定义为final,90%以上的文章都说"当你在方法中不需要改变作为参数的对象变量时,明确使
用final进行声明,会防止你无意的修改而影响到调用方法外的变量。"
胡说八道!

我不知道这个修改是说重新赋值还是修改对象本身,但无论是哪种情况,上面的说法都是错误的.
如果是说重新赋值,那么:
 public static void test(int[] x){
  x = new int[]{1,2,3};
 }

    int[] out = new int[]{4,5,6};
    test(out);
    System.out.println(out[0]);
    System.out.println(out[1]);
    System.out.println(out[2]);

    调用test(out);无论如何也不会影响到外面变量out.你加不加final根本没有意义.final只会强迫方法内
多声明一个变量名而已,即把x = new int[]{1,2,3};改成int y = new int[]{1,2,3}; 其它没有任何实际意义.
    如果说是修改对象本身:
public static void test(final int[] x){
  x[0] = 100;
 }
    int[] out = new int[]{4,5,6};
    test(out);
    System.out.println(out[0]);

难道你用final修饰就不可以修改了?所以说对于方法参数中final是为了不影响调用方法外的变量那是胡说八道的.

那我们到底为什么要对参数加上final?其实对方法参数加final和方法内变量加上final的作用是相同的,即为了将它们
传给内部类回调方法:
abstract class ABSClass{
 public abstract void m();
}

现在我们来看,如果我要实现一个在一个方法中匿名调用ABSClass.应该:
public static void test(String s){
     //或String s = "";
  ABSClass c = new ABSClass(){
   public void m(){
      int x = s.hashCode();

      System.out.println(x);

   }
  };
  //其它代码.
 }

注意这里,一般而言,回调方法基本上是在其它线程中调用的.如果我们在上面的
  
  ABSClass c = new ABSClass(){
   public void m(){
       int x = s.hashCode();

       System.out.println(x);

   }
  };

  后面直接调用c.m();应该是没有意义的.但这不重要,重要的是只要有可能是在其它线程中调用,那我们就必须
为s保存引用句柄.

我们先来看GC工作原理,JVM中每个进程都会有多个根,每个static变量,方法参数,局部变量,当然这都是指引用类型.
基础类型是不能作为根的,根其实就是一个存储地址.

GC在工作时先从根开始遍历它引用的对象并标记它们,如此递归到最末梢,所有根都遍历后,没有被标记到的对象说明没
有被引用,那么就是可以被回收的对象(有些对象有finalized方法,虽然没有引用,但JVM中有一个专门的队列引用它
们直到finalized方法被执行后才从该队列中移除成为真正没有引用的对象,可以回收,这个与本主题讨论的无关,包括
代的划分等以后再说明).这看起来很好.

但是在内部类的回调方法中,s既不可能是静态变量,也不是方法中的临时变量,也不是方法参数,它不可能作为根,在内部类
中也没有变量引用它,它的根在内部类外部的那个方法中,如果这时外面变量重指向其它对象,则这个对象就失去了引用,
可能被回收,而由于内部类回调方法大多数在其它线程中执行,可能还要在回收后还会继续访问它.这将是什么结果?

而使用final修饰符不仅会保持对象不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期.所以这才是final
变量和final参数的根本意义.
    
分享到:
评论
1 楼 wuyufeixue 2010-07-22  
final变量可以在任何可以被始化的地方被始化?不是吧,在声明的地方,构造函数,main函数等可以保证final变量初始化的地方吧,final变量必须要保证初始化吧

相关推荐

    java final变量详解

    Java final 变量详解 Java 中的 final 变量是指不能被改变的变量,它有三个方面的作用:修饰变量、修饰方法和修饰类。在 Java 中,final 变量是一种常量,它只能被赋值一次,赋值后值不再改变。 final 变量的使用...

    局部变量用final的讨论

    标题中的“局部变量用final”的讨论主要聚焦于Java编程语言中的一个特性,即使用`final`关键字修饰局部变量。在Java中,`final`关键字有多种用途,包括但不限于定义不可变对象、创建常量以及限制变量的赋值次数。在...

    final修饰成员变量和局部变量.md

    本文章是关于final部分知识所作的自我总结,内容为final对成员变量和局部变量修饰的简要解答,除了对自我java学习的一个小结,也希望能够帮助到在java路上对该内容疑惑的同行

    final变量.

    `final`变量确保其值在赋值后不会被修改,从而提供了数据的安全性和一致性。这在多个方面都有其优势,包括效率、设计约束以及代码优化。 1. **效率问题**: `final`关键字有时用于效率考虑,特别是当一个方法被...

    Eclipse设置保存时自动给变量加final

    标题“Eclipse设置保存时自动给变量加final”涉及到的是在Eclipse集成开发环境中(IDE)进行代码风格和规范配置的技巧。Eclipse是一个广泛使用的Java IDE,它提供了丰富的功能和自定义选项,以满足不同开发者的需求...

    final类,方法,变量

    本篇文章将深入探讨`final`关键字在类、方法和变量中的应用,以及它们对程序设计的影响。 首先,让我们了解`final`关键字在类中的使用。当一个类被声明为`final`时,这意味着它不能被继承。这意味着这个类是封闭的...

    深入理解final变量的初始化

    在Java编程语言中,`final`关键字用于声明不可变的变量。这些变量一旦被初始化,就不能再更改其值。深入理解`final`变量的初始化至关重要,因为它涉及到程序的正确性和内存管理。以下是对`final`变量初始化的详细...

    深入理解Java final变量的内存模型

     在构造函数内对一个 final 域的写,与随后把这个构造对象的引用赋值给一个变量,这两个操作之间不能重排序  初次读一个包含 final 域的对象的引用,与随后初次读这个 final 域,这两个操作之间不能重排序  举...

    java_中的_final_变量[文].pdf

    在Java编程语言中,`final`关键字扮演着重要的角色,它用于声明不可变的变量、方法和类。理解`final`的关键在于其不可变性,这有助于提高程序的效率、稳定性和设计规范。 首先,`final`变量表示常量,一旦赋值后就...

    JavaSE之final关键字与成员变量的类型

    【JavaSE之final关键字与成员变量的类型】 在Java编程语言中,`final`关键字扮演着重要的角色,它表示“最终”或“不可改变”的特性。对于初学者来说,理解`final`的关键字用法是掌握JavaSE基础的重要一步。本篇...

    final和static用法详解JAVA

    final 修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。final 变量定义的时候,可以先声明,而不给初值,这中变量也称为 final 空白,无论什么情况,编译器都确保空白 final 在使用之前...

    Java中final的深度剖析

    在Java 8引入的lambda表达式中,final变量可以作为lambda的捕获变量,这保证了lambda表达式的封闭性,即它们不能修改外部的非final变量。 总结来说,final关键字在Java编程中扮演了多种角色,从确保常量的不变性,...

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

    ### Java中局部内部类可以访问它所在方法中定义的final修饰的局部变量的合理解释 #### 背景介绍 在Java编程语言中,局部内部类(Local Inner Class)是一种特殊的内部类形式,它被定义在某个方法或构造器的内部。...

    day11 05 final关键字用于修饰成员变量

    day11_05_final关键字用于修饰成员变量

    Java中final作用于变量、参数、方法及类该如何处理

    在本文中,我们将深入探讨`final`在变量、参数、方法和类中的应用及其作用。 **1. `final`关键字用于变量** - **final基本类型变量**:当`final`用于基本类型的变量时,它被视为常量,一旦赋值后就不能更改。尝试...

    Java中final变量使用总结

    当我们在声明变量时使用`final`,我们确保该变量的值一旦被赋值,就不能再次改变。这使得`final`变量成为常量,它们在程序执行期间保持不变。 1. **final变量的声明** - 对于基本类型变量,如`int`、`double`等,...

    Java关键字final、static使用总结

    final 变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。 4、final 参数 final 参数可以读取使用该参数,但是无法改变该参数的值。 二、static 关键字 static 关键字可以用来修饰成员变量和...

    javafinal和static总结.docx

    final 变量是值一旦给定就无法改变的变量,final 变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。 例如: `private final String S = "final 实例变量 S";` final 变量定义的时候,可以先...

    Java中的final关键字

    - 在创建匿名内部类时,如果需要访问外部类的局部变量,该变量必须是`final`或实际上等效于`final`的。这是因为匿名内部类可能在外部方法执行完成后仍然存在,所以需要确保引用的变量不会在内部类的生命周期内改变...

Global site tag (gtag.js) - Google Analytics