java之final

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编程思想

http://stackoverflow.com/questions/1299837/cannot-refer-to-a-non-final-variable-inside-an-inner-class-defined-in-a-differen



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值