深入Final关键字
来源:互联网 发布:淘宝刷佣金是真是假 编辑:程序博客网 时间:2024/05/22 23:27
1.类的final变量和普通变量有什么区别?
public class FinalTest { public static void main(String[] args) { String a = "hello2"; final String b = "hello"; String d = "hello"; String c = b + 2; String e = d + 2; System.out.println((a == c)); System.out.println((a == e)); System.out.println((a.equals(e))); System.out.println("结果是:-true------false--true"); }}
结果是:true false true
public class FinalTest { public static void main(String[] args) { String a = "hello2"; final String b = getHello(); String c = b + 2; System.out.println((a == c)); System.out.println("结果是:--false--"); } public static String getHello() { return "hello"; }}
结果是:false
原因:
第一个结果是true,第二个结果是false。这里面就是final变量和普通变量的区别,当final变量是基本数据类型以及String类型时,付过在编译期间能知道它的确切值,则编译会把它当做编译期常量使用。也就是说在用到该final变量的时候,相当于直接访问这个常量,不需要再运行时确定。这种和C语言中的宏替换有点儿像。因此变量b被final修饰,因此会被当做编译期常量,所以在使用到b的地方直接将变量b替换为它的值。而对于变量d的访问却需要在运行时通过连接来进行。注意在只有在编译期间能确切知道final变量的情况下才会进行这样的优化。
2.被final修饰的引用变量指向的对象内容可变吗?
package com.wisdom.effective.java;public class FinalTest_2 { public static void main(String[] args) { final MyClass myClass = new MyClass(); System.out.println(++myClass.i); }}class MyClass { public int i = 0;}
结果是:1
原因:
这段代码可以顺利编译通过并且有输出结果,输出结果为1。这说明引用变量被final修饰之后,虽然不能再指向其他对象,但是它指向的对象的内容是可变的。
3.final和static
package com.wisdom.effective.java;public class FinalTest_2 { public static void main(String[] args) { MyClass myClass1 = new MyClass(); MyClass myClass2 = new MyClass(); System.out.println(myClass1.i); System.out.println(myClass1.j); System.out.println(myClass2.i); System.out.println(myClass2.j); }}class MyClass { public final double i = Math.random(); public static double j = Math.random();}
结果是:0.05766174928636447
0.7614580638924601
0.9017659828502815
0.7614580638924601
运行这段代码就会发现,每次打印的两个j值都是一样的,而i的值却是不同的。
原因是:
很多时候会容易把static和final关键字混淆,static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变。
4.匿名内部类中使用的外部局部变量为什么只能是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和Test1.class。默认情况下,编译器会为匿名内部类和局部内部类起名为Outter1.class。默认情况下,编译器会为匿名内部类和局部内部类起名为Outterx.class(x为正整数)。
根据上图可知,test方法中的匿名内部类的名字被起为 Test$1。
上段代码中,如果把变量a和b前面的任一个final去掉,这段代码都编译不过。我们先考虑这样一个问题:
当test方法执行完毕之后,变量a的生命周期就结束了,而此时Thread对象的生命周期很可能还没有结束,那么在Thread的run方法中继续访问变量a就变成不可能了,但是又要实现这样的效果,怎么办呢?Java采用了 复制 的手段来解决这个问题。
5.关于final参数的问题
关于网上流传的”当你在方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法外的变量“这句话,我个人理解这样说是不恰当的。
因为无论参数是基本数据类型的变量还是引用类型的变量,使用final声明都不会达到上面所说的效果。
看这个例子就清楚了:
上面这段代码好像让人觉得用final修饰之后,就不能在方法中更改变量i的值了。殊不知,方法changeValue和main方法中的变量i根本就不是一个变量,因为java参数传递采用的是值传递,对于基本类型的变量,相当于直接将变量进行了拷贝。所以即使没有final修饰的情况下,在方法内部改变了变量i的值也不会影响方法外的i。
再看下面这段代码:
package com.wisdom.effective.java;
public class FinalTest_4 { public static void main(String[] args) { MyClass_3 myClass = new MyClass_3(); StringBuffer buffer = new StringBuffer("hello"); myClass.changeValue(buffer); System.out.println(buffer.toString()); }}class MyClass_3 { void changeValue(final StringBuffer buffer) { buffer.append("world"); }}
结果是:holleword
原因是:
运行这段代码就会发现输出结果为 helloworld。很显然,用final进行修饰并没有阻止在changeValue中改变buffer指向的对象的内容。有人说假如把final去掉了,万一在changeValue中让buffer指向了其他对象怎么办。有这种想法的朋友可以自己动手写代码试一下这样的结果是什么,如果把final去掉了,然后在changeValue中让buffer指向了其他对象,也不会影响到main方法中的buffer,原因在于java采用的是值传递,对于引用变量,传递的是引用的值,也就是说让实参和形参同时指向了同一个对象,因此让形参重新指向另一个对象对实参并没有任何影响。
所以关于网上流传的final参数的说法,我个人不是很赞同。
把final去掉
package com.wisdom.effective.java;public class FinalTest_4 { public static void main(String[] args) { MyClass_3 myClass = new MyClass_3(); StringBuffer buffer = new StringBuffer("hello"); myClass.changeValue(buffer); System.out.println(buffer.toString()); }}class MyClass_3 { void changeValue(StringBuffer buffer) { buffer.append("world"); }}
结果仍然是:holleword
- 深入理解 final 关键字
- 深入Final关键字
- 深入理解final关键字
- 深入理解final关键字
- 深入理解final关键字
- 深入理解final关键字
- final关键字的深入理解
- java final关键字深入理解
- java基础:final关键字的深入使用
- 深入理解Java中的final关键字
- 深入理解Java中的final关键字
- 深入理解Java中的final关键字
- 深入理解Java中的final关键字
- 深入理解Java中的final关键字
- java关键字 final 的深入使用
- 深入理解Java中的final关键字
- 深入理解Java中的final关键字
- java基础:final关键字的深入使用
- Servlet异常处理
- ROS中用摇杆控制电机(四个电机转动)
- 设计模式学习之路 - 序言 - 记录自己的成长历程
- 最好的规划就是天衣无缝,让人无机可乘
- 如何选择真静态和伪静态?
- 深入Final关键字
- Jquery 选择 select 、radio 的几种方式
- 弹性图片
- HTTP请求头大全
- Android录音并播放(mp3或amr格式)
- 实体类(VO,DO,DTO)的划分
- db2数据库的启动和关闭
- 无判断max
- 插入排序