final 这个关键字从学Java开始就有提及。它可以用来修饰class, method, method parameter, variable等。这里主要说说最后这一种。
对于有final 修饰的variable, 无论是instance variable 还是local variable, 其含义是说(一般)一经初始化和赋值,其值就无法改变。这里,对于instance variable, 我们说,这“初始化和赋值”可能是在声明时就完成的,也可以是在构造函数中完成的。
然而,这个一般无法改变的值却是可以改变的。在JSR 133 中提到了用反射改变final 的instance field 的方法。这里截取的是那里面的例子:
class A ...{
final int x;
A() ...{
x = 1;
}
int f() ...{
return d(this,this);
}
int d(A a1, A a2) ...{
int i = a1.x;
g(a1);
int j = a2.x;
return j - i;
}
static void g(A a) ...{
// uses reflection to change a.x to 2
}
}
在JDK1.4 以及它以前的版本中,这种方法是行不通的。而在JDK 5 中,这种方法却可行的。具体做法是分别调用Field 的setAccessible(true) 方法和setX 方法进行赋值。
但是,这种方法可能会因为reorder 导致问题。JSR133 中说到:
... Another problem is that the semantics is designed to allow aggressive optimization of final fields.
Within a thread, it is permissible to reorder reads of a final field with calls to methods that may
change final fields via reflection.
所以,在JSR 133 中,提出了Final Field Safe Context 的概念。这个名词的意思是,在这个context 中,可以保证不会发生reorder 的现象。但奇怪的是,现在JVM 的实现中,似乎没有为这个语义定义关键字。
说到final, 顺便说一下static final. static final 在类初始化以后,几乎都不能改变。这里说“几乎” 的原因是有例外:
Static final fields may only be modified in the class initializer that defines them, with the exception
of the java.lang.System.in, java.lang.System.out, and java.lang.System.err static fields, which can be modified by the java.lang.System.setIn, java.lang.System.setOut, and java.lang.System.setErr methods.
另外,顺便说一下,对于有无static 修饰的final field, 其在JVM 内部的初始化函数是不同的。这个有兴趣的可以看一下后面的参考文档。
最后要说的是所谓值“不能改变”的意思。概括的说,对于primitive 类型的变量,一旦声明为final, 除了上面的情况,初始化后就不能改了。而对于对象类型的field, “不能改变”的是它的引用。要理解这句话的意思,请看一下这段代码:
package com.dproxy;
import java.util.ArrayList;
public class FinalChangeTest {
public final int a = 3;
public final Object b = null;
public final String c = "abc";
public final StringBuffer d = new StringBuffer("a");
public final ArrayList e = new ArrayList();
public final TestClass f = new TestClass();
public final int[] g = new int[3];
public static void main(String args[]){
FinalChangeTest test = new FinalChangeTest ();
// test.a = 4; // error
// test.b = ""; //error
// test.c = ""; //error
// test.d = test.d.append("ttt"); //error
test.d.setCharAt(0, 'c');
test.e.add("");
// System.out.println(test.f.i); //1
test.f.i = 2;
// System.out.println(test.f.i); //2
test.g[0] = 3;
}
class TestClass{
public int i = 1;
}
public void finalVarTest(){
final int a = 3;
final Object b = null;
final String c = "abc";
final StringBuffer d = new StringBuffer("a");
final ArrayList e = new ArrayList();
final TestClass f = new TestClass();
final int[] g = new int[3];
// a=2; //error
// b="";//error
// c="";//error
d.setCharAt(0, 'c');
e.add("");
f.i = 0;
g[1] = 2;
}
}
上面代码里注释部分的句子都是无法通过编译的。对比这个,读者可以理解一下。
参考:
JSR133
http://www.cs.umd.edu/~pugh/java/memoryModel/archive/2398.html
http://dev2dev.bea.com.cn/bbsdoc/20060704286.html
分享到:
相关推荐
static final Logger logger = Logger.getLogger(Main.class); public static void main(String[] args) { logger.info("Program started."); // ... } } ``` 这里的`Logger.getLogger(Main.class)`根据类名...
再来说说volatile关键字。volatile是Java中的一种轻量级同步机制,它能够保证共享变量的可见性,但不保证原子性。当一个变量被声明为volatile时,每次修改都会立即刷新到主内存,其他线程可以立即看到修改。但是,...
自己写一个小程序,我在java1.6.0_10;smslib-v3.4.5下运行成功,主要是以下几个类. Level_Final_Serial.java:串口底层操作 ...http://blog.csdn.net/yangzl0123/archive/2010/03/02/5339263.aspx说说您的看法).
final V putVal(K key, V value, boolean onlyIfAbsent){ if (key == null || value == null) throw new NullPointerException(); int hash = spread(key.hashCode()); int binCount = 0; for (Node,V>[] tab = ...
enum实现 JDK5中提供了Java枚举类型的实现,与其说是一种新类型,... public final class Season extends Enum { public static Season[] values() { return (Season[])$VALUES.clone(); } public static Season
final String path = listUrls.get(position); Glide.with(MainActivity.this) .load(new File(path)) .placeholder(R.mipmap.default_error) .error(R.mipmap.default_error) .centerCrop() .crossFade() ....
3、说说&和&&的区别。 4、在JAVA中如何跳出当前的多重嵌套循环? 5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 6、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么...
接下来说说数据库操作。Android原生支持SQLite数据库,它是轻量级的关系型数据库,适合存储应用数据。首先,你需要创建一个`SQLiteOpenHelper`子类,用于数据库的创建和版本管理: ```java public class ...
http://blog.csdn.net/yangzl0123/archive/2010/03/02/5339263.aspx说说您的看法). 时间:2010-3-3 12:15 ********************************************************************** smslib版本已经更新:...
final 修饰符的理解 说说你对泛型的理解 泛型中 extends 和 super 的区别 描述下 Java 中的异常处理机制 什么是 HashMap,描述下其实现原理 HashMap、Hashtable 和 HashSet 这三者有什么联系和区别 列举下 Java 的...
上章讲了访问控制符,这章开始讲非访问控制符。 java中的非访问修饰符的作用各不一样,据我所知常用的有六种: static final abstract ...首先我们来说说static: 被static修饰的方法我们称为静态方
再来说说**SQLite数据库**,它是Android内置的关系型数据库。适用于存储结构化的数据,如用户信息、任务列表等。通过`SQLiteOpenHelper`子类创建数据库和表,然后使用`SQLiteDatabase`进行查询和操作。下面是一个...
#### 简单说说你了解的类加载器。是否实现过类加载器 类加载器是Java虚拟机的一部分,负责将字节码加载到内存中,并转换为可执行的类。Java中有多种类加载器,包括Bootstrap ClassLoader、Extension ClassLoader和...
4. **说说&和&&的区别** - &是位运算符,用于按位进行逻辑与操作,而&&是逻辑与运算符,只有当左侧表达式为真时才会评估右侧表达式,这是一种短路逻辑操作。 5. **在JAVA中如何跳出当前的多重嵌套循环?** - 使用...
3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 9 6、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有...
9. 请说一下 final,finally 和 finalize 的区别。 10. 请说一下 HTTP 请求的基本过程。 11. Java 中存在内存泄漏问题吗?请举例说明。 12. 请说一下 Java 中的内存回收机制所采用的算法。 13. 请说一下 System.gc()...
3、说说&和&&的区别。 4 4、在JAVA中如何跳出当前的多重嵌套循环? 4 5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 5 6、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有...
3. **说说&和&&的区别。** &是逻辑与运算符,无论两侧表达式是否为真都会进行计算;而&&是短路与运算符,如果左侧表达式为假,右侧表达式将不会被计算。这在处理方法调用或可能抛出异常的情况时尤其重要。 4. **在...
3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 9 6、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有...
3. **说说 & 和 && 的区别。** `&` 是按位与运算符,而 `&&` 是逻辑与运算符。`&&` 有短路特性,如果左侧表达式为假,它不会评估右侧表达式;`&` 总是评估两边的表达式。 4. **在JAVA中如何跳出当前的多重嵌套循环...