final变量
final变量有以下2种
(1) 编译期常数,它永远不会改变,如下i1,I2,I3
(2) 在运行期初始化的一个值,我们不希望它发生变化,如i4,i5,i6
注意i6 必须在构造函数里显示赋值,不能想着他会默认赋0,否则编译出错
public class FinalData {
// Can be compile-time constants
final int i1 = 9;
static final int I2 = 99;
// Typical public constant:
public static final int I3 = 39;
// Cannot be compile -time constants:
final int i4 = (int) (Math.random() * 20);
static final int i5 = (int) (Math.random() * 20);
//Must be init in constructor
final int i6;
public FinalData()
{
i6=10;
}
}
final方法
无法被重写。
同时告诉编译器,这个方法可以考虑inline,可以提高效率
通常,只有在方法的代码量非常少,或者想明确禁止方法被覆盖的时候,才应考虑将一个方法设为final
类内所有 private 方法都自动成为 final。由于我们不能访问一个 private 方法,所以它绝对不会被其他方法覆盖(若强行这样做,编译器会给出错误提示)
除了final属性或者变量之外,很多资料上也会提到final方法对程序的性能也是由帮助的。编译器对final方法能够做的优化其实很有限,可以说基本是干不了什么事情的。这是由继承引起的问题,由于子类在覆写父类的方法时,是可以将final关键字抹去的,因此编译器是没有足够多的信息来优化final方法的。final方法的优化是在运行期由虚拟机根据程序的执行情况来完成的,优化采用就是内联。
内部类与final
public class A {
public interface IMan
{
void Study();
}
public void init(int m)
{
final int x=m+3;
IMan man=new IMan() {
@Override
public void Study() {
int t=x;
}
};
}
}
内部类想要用到外部方法里的临时变量x,就需要把x加上final,否则编译错误。
为什么要这样呢?
实际上内部类里面有2个成员变量,一个指向外部类的this指针,还有一个就是int值,由x传入
看A$1的class文件(用eclipse打开),A$1代表A的第一个内部类
01 class com.example.abcc.A$1 implements com.example.abcc.A$IMan {
02
03 // Field descriptor #8 Lcom/example/abcc/A;
04 final synthetic com.example.abcc.A this$0;
05
06 // Field descriptor #10 I
07 private final synthetic int val$x;
08
09 // Method descriptor #12 (Lcom/example/abcc/A;I)V
10 // Stack: 2, Locals: 3
11 A$1(com.example.abcc.A arg0, int arg1);
12 0 aload_0 [this]
13 1 aload_1 [arg0]
14 2 putfield com.example.abcc.A$1.this$0 : com.example.abcc.A [14]
15 5 aload_0 [this]
16 6 iload_2 [arg1]
17 7 putfield com.example.abcc.A$1.val$x : int [16]
18 10 aload_0 [this]
19 11 invokespecial java.lang.Object() [18]
20 14 return
21 Line numbers:
22 [pc: 0, line: 1]
23 [pc: 10, line: 10]
24 Local variable table:
25 [pc: 0, pc: 15] local: this index: 0 type: new com.example.abcc.A(){}
26
27 // Method descriptor #20 ()V
28 // Stack: 1, Locals: 2
29 public void Study();
30 0 aload_0 [this]
31 1 getfield com.example.abcc.A$1.val$x : int [16]
32 4 istore_1 [t]
33 5 return
34 Line numbers:
35 [pc: 0, line: 15]
36 [pc: 5, line: 16]
37 Local variable table:
38 [pc: 0, pc: 6] local: this index: 0 type: new com.example.abcc.A(){}
39 [pc: 5, pc: 6] local: t index: 1 type: int
40
41 Inner classes:
42 [inner class info: #1 com/example/abcc/A$1, outer class info: #0
43 inner name: #0, accessflags: 0 default],
44 [inner class info: #5 com/example/abcc/A$IMan, outer class info: #30 com/example/abcc/A
45 inner name: #36 IMan, accessflags: 1545 public abstract static]
46 Enclosing Method: #30 #32 com/example/abcc/A.init(I)V
47 }看代码,第4行有个指向外部类的引用,第7行有个int值。再看第11行A$1(com.example.abcc.A arg0, int arg1);这是构造函数,传进来一个A,一个int,这种实现方式叫copy local value.
好像还是没讲final的原因啊,我们来看看没有final会发生什么事情
public void init(int m)
{
int x=3;
IMan man=new IMan() {
@Override
public void Study() {
// TODO Auto-generated method stub
int t=x;
}
};
x=10;
}
我们来看上面一段代码,没有final,init最后x为10,但是传入内部类里的x是3,内部类的成员变量x也是3,
内部类.x=3
方法里的x=10
但是在java开发者看来,这2个x是同一个x,不该出现2个值,所以编译器规定必须用final,防止方法里改变局部变量的值。
网上很多人说是生存期的问题,内部类的生存期会比局部变量生存期长,函数结束了,函数栈帧退栈,就无法访问局部变量了,所以加上final,其实加上final,你也无法访问到局部变量,此处实际上是拷贝了一份作为内部类的成员变量来实现的
如何修改final变量
参考资料
http://developer.51cto.com/art/200906/128214.htm
http://mysun.iteye.com/blog/1580916(好文章)
java编程思想
1291

被折叠的 条评论
为什么被折叠?



