java final变量

final变量定义: 变量一经初始化就不能指向其它对象。指向的存储地址不可修改,但指向的对象本身是可以修改的。

先说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参数的根本意义.

时间: 2024-11-05 02:41:20

java final变量的相关文章

再说java final变量

http://blog.csdn.net/axman/article/details/1460544 从jdk1.0到今天,JAVA技术经过十余年的发展,技术上已经发生了巨大的变化.但final变量的定义从它 诞生那天起,就没有发生任何变化,也就是这十多年它就一直表示它原来的意思. 但遗憾的是,经过十多年仍然有90%的人没有理解它的真实含义,也没有一篇文章,包括我所见到的所有介绍 JAVA的书籍(包括TKJ)都没有说清楚,我相信肯定有些作者是理解的,但没有一个作者向读者说清楚.而中国网友 大多数

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

对于 final 域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个 final 域的写,与随后把这个构造对象的引用赋值给一个变量,这两个操作之间不能重排序 初次读一个包含 final 域的对象的引用,与随后初次读这个 final 域,这两个操作之间不能重排序 举个例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class FinalExample {     int i;// 普通变量     final i

【JAVA】在编译期可直接替换的final变量

一.满足以下三个条件,一个final变量就不再是一个变量,而是一个直接量. 使用final修饰符修饰. 在申明的时候就进行初始化 初始化的值在编译器就可以确定. 二.在什么情况下初始化的值在编译期是可以确定下来的? 被赋的表达式只是基本的算术表达式或字符串链接运算,没有访问普通变量,调用方法. package fianlFieldCase; public class Test { public static void main(String[] args) { final String str1

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

先看下面这段代码: public class Test { public static void main(String[] args) { } public void test(final int b) { final int a = 10; new Thread(){ public void run() { System.out.println(a); System.out.println(b); }; }.start(); } } 这段代码会被编译成两个class文件:Test.class

随笔⑨ java中的变量 --- 类变量(静态变量),final变量,成员变量,局部变量

java中的变量 --- 类变量(静态变量),final变量,成员变量,局部变量 ① 类变量(也叫静态变量)是类中独立于方法之外的变量,用static 修饰,静态变量随着类的加载而加载. ② final变量:用final关键字修饰,不能被修改.与static一起用可表示常量. ③ 成员变量(也叫"实例变量"."域"):也是类中独立于方法之外的变量,不过没有static修饰.可以不进行初始化,Java会自动进行初始化,如果是引用类型默认初始化为null,如果是基本类型

Java基础-final变量和普通变量的区别

当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了. 那么final变量和普通变量到底有何区别呢?下面请看一个例子: public class Test { public static void main(String[] args) { String a = "hello2"; final String b = "he

stactic final和final变量的初始化(in java)

1.static final(常量) 初始化可以有两种方法: (1)在声明的时候初始化 static final i = 1; 你也可以将一个静态方法的返回值设置给它 static final int i = f(); static public int f(){ return 1; } (2)在静态代码快中初始化(一般情况下,如果有些代码必须在项目启动的时候就执行的话,需要使用静态代码块,这种代码是主动执行的;一个类可以使用不包含在任何方法体中的静态代码块,当类被载入时,静态代码块被执行,且只

java中变量命名和引用变量的一个坑

这次有两个主题,第一个太简单啦,就是java中变量的命名规则,纯记忆性东西.第二个主题,就是讨论一下对象引用变量的一个注意点. 如果你对命名规则很熟啦,就直接看第二个内容吧.(上边的图稍微有点顺序紊乱啊) 一.java中变量的命名规则 大多数语言的命名规则是相似的,只有一些微小的差别. 变量的第一个位置,可以是字母,下划线(_),美元符($) (这个在c/c++,python中是不行的)(注意:不能是数字哦,一想就知道啦为什仫) 其他的位置可以是数字,字母,下划线 不能使用java中的关键字 j

[java]final关键字、finally关键字与finalize()方法

final关键字: final关键字通常指的是“无法改变的”,使用“无法改变”这样修饰可能出于两个原因:设计或者效率. final可以修饰变量.方法和类. 一.final变量 一个既是static又是final的域只占据一段不能改变的存储空间. 当对对象引用而不是基本类型运用final修饰时,其含义会有一点迷惑.对于基本类型,final使数值恒定不变.而用于对象引用,final使引用恒定不变.一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象.然而,对象自身却是可以修改的,java并未