final的深入使用

java中的final关键字:

final可以修饰变量,被final修饰的变量被赋值之后,不能对它重新赋值

final可以修饰方法,被final修饰的方法不能被重写

final可以修饰类,被final修饰的类不能派生子类

 

 

1)final修饰变量

被final修饰的变量必须显式指定初始值,且只能在下面3个位置指定初始值:

定义final实例变量时指定初始值

在非静态代码块中为final实例变量指定初始值

在构造器中为final实例变量指定初始值

使用javap工具编译final修饰的实例变量可以看到,变量的赋值都是放在构造方法中执行的,理论上说final修饰的实例变量的初始化只能

在构造方法中进行。

 

 

同样对于final修饰的类变量也必须指定初始值,且只能在2个地方指定初始值:

定义final的类变量时指定初始值

在静态代码块中为final类变量指定初始值

使用javap工具编译final修饰的类变量可以看到,变量的赋值都是放在静态代码块中执行的,理论上说final修饰的类变量的初始化只能

在静态代码块中进行。

 

 

2)宏变量

请先看http://blog.csdn.net/xxqi1229/article/details/6905188中的关于"类变量与实例变量的初始化过程"下面的程序是在原来的程序

上面稍作修改后的。

请看程序:

public class Price {

final static Price INSTANCE = new Price(2.8) ;

final static double initPrice = 20  ;//此变量声明为final类型,此处和源程序不同。

double currentPrice ;

public Price(double discount){

currentPrice = initPrice - discount ;

}

}

测试用例如下:

public class Test {

public static void main(String[] args) {

System.out.println(Price.INSTANCE.currentPrice);

Price p = new Price(2.8) ;

System.out.println(p.currentPrice);

}

}

此时程序的运行结果为:

17.2

17.2

(注:原来程序的运行结果为-2.8 17.2)

为什么加上final关键字后结果就变为17.2呢?对于一个用final修饰的变量而言,如果定义该final变量的时就指定了初始值,而且这个

初始值在编译的时候就可以确定下来,那么这个变量将不再是一个变量,系统会将其当成一个“宏变量”处理,也就是说,在程序中出现

该变量的地方全部把它当成对应的值来处理。

什么叫值在编译时可以确定下来。比如说String s = "aaaaaa";此时在编译的时候就可以确定下来为“aaaaaa”,但是如果定义为

String s = str ;str也是一个字符串类,则此时编译的时候就不能确定s的值是多少。

对于上面的程序而言,由于使用了final关键字修饰initPrice类变量,因此Price类的构造器中执行currentPrice=initPrice-discount;的

时候会将initPrice直接替换为20.因此,执行该代码效果相当于currentPrice=20-discount;

如果把程序中定义initPrice的代码改为如下:

static double d = 20 ;

final static double initPrice = d  ;

则程序运行结果为:

-2.8

17.2

这事因为在编译initPrice的时候不能确定initPrice的值。

 

 

3)宏替换

对于一个final变量,不管它是类变量,实例变量还是局部变量,只要定义了该变量时使用了final修饰符修饰,并在定义该final类变量的

时候指定了初始值,而且该初始值可以在编译的时候就确定下来,那么这个final变量本质上已经不再是一个变量,而是一个直接量(宏)。

请看如下程序:

public class Test {

public static void main(String[] args) {

String str1 = "疯狂";

String str2 = "java" ;

final String str3 = "疯狂java";

final String str4 = "疯狂" + "java";

final String str5 = str1 + str2 ;

final String str6 = "疯狂" + String.valueOf("java") ;

 

System.out.println(str3 == str4);

System.out.println(str3 == str5);

System.out.println(str3 == str6);

}

}

程序运行结果为:

true

false

false

str3 == str4的结果为true,这是因为str4在编译的时候就确定了值。

str3 == str5的结果为false,这事因为str5在编译的时候不能确定值,因为str1和str2不是final类型的,如果把str1和str2定义为final

类型,则str5在编译的时候就可以确定值,此时结果就应该为true。

str3 == str6的结果为false,这是因为表达式中使用了String的方法valueOf,因此在编译的时候无法确定str6的值。

 

 

注:对于宏变量只有在定义该变量的时候赋初始值才会有“宏变量”的效果,在非静态代码块、构造方法中为fianl实例变量指定初始值则不会

有这样的效果。

请看下面的程序:

public class FinalInitTest {

final String str1 ;

final String str2 ;

final String str3 = "java" ;

{//非静态代码块中初始化s

str1 = "java" ;

}

public FinalInitTest(){//构造方法中初始化

str2 = "java" ;

}

public void display(){

System.out.println(str1 + str1 == "javajava");

System.out.println(str2 + str2 == "javajava");

System.out.println(str3 + str3 == "javajava");

}

 

public static void main(String[] args){

FinalInitTest fit = new FinalInitTest() ;

fit.display() ;

}

}

程序的运行结果为:

false

false

true

从程序结果中可以看出,str1和str2没有达到宏替换的母的,这是因为str1在初始化在飞静态代码块中,str2的初始化在构造方法中。

只有在定义final变量的时给定初始值(编译的时候可以确定值)才会达到宏替换的效果。静态final类型的变量也一样。

 

 

3)final变量在内部类中的使用

程序需要在匿名内部类中使用局部变量,则局部变量必须声明为final类型。否则会编译错误。为什么必须声明为final类型呢?这是应为

对于普通变量而言,它的作用域是停留在该方法内,当方法执行结束,该局部变量也就随之消失,但内部类则可能产生隐式的“闭包”,

闭包使得局部变量脱离它所在的方法继续存在。

看下面的例子:

public class ClosureTest {

public static void main(String[] args) {

final String str = "java" ;//定义局部变量

 

new Thread(new Runnable(){

public void run(){

for(int i=0 ;i<100 ; i++){

System.out.println(str + i);

try {

Thread.sleep(100) ;

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}).start() ;

}

}

程序首先定义了一个局部变量str,当程序main方法执行完成后,str的生命周期就结束了,但是子线程还没有执行结束,而且子线程要

使用main中的局部变量str,这个时候就扩大了str的作用范围。这个时候如果str没有被修饰为final类型,而可以随便改变,则会引起

极大的混乱,因此java编译器要求所有的内部类访问的局部变量必须使用final修饰符修饰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值