final、finally、finalize 区别
原文出处 : http://wenku.baidu.com/view/2d4593d0ce2f0066f533224a.htm
Final 用于声明属性,方法,类,分别表示属性不可变,方法不可重写,类不可继承。
1. 属性不可变
当你在类中定义变量时,在其前面加上final关键字,那便是说,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变。其初始化可以在两个地方,一是其定义处,也就是说在final变量定义时直接给其赋值,二是在构造函数中。这两个地方只能选其一,要么在定义时给值,要么在构造函数中给值,不能同时既在定义时给了值,又在构造函数中给另外的值。下面这段代码演示了这一点:
4. public class Bat{ 5. final PI=3.14; //在定义时便给址值 6. final int i; //因为要在构造函数中进行初始化,所以此处便不可再给值 7. final List list; //此变量也与上面的一样 8. Bat(){ 9. i=100; 10. list=new LinkedList(); 11. } 12. Bat(int ii,List l){ 13. i=ii; 14. list=l; 15. } 16. public static void main(String[] args){ 17. Bat b=new Bat(); 18. b.list.add(new Bat()); 19. //b.i=25; 20. //b.list=new ArrayList(); 21. System.out.println("I="+b.i+" List Type:"+b.list.getClass()); 22. b=new Bat(23,new ArrayList()); 23. b.list.add(new Bat()); 24. System.out.println("I="+b.i+" List Type:"+b.list.getClass()); 25. } 26. }
此程序很简单的演示了final的常规用法。在这里使用在构造函数中进行初始化的方法,这使你有了一点灵活性。如Bat的两个重载构造函数所示,第一个缺省构造函数会为你提供默认的值,重载的那个构造函数会根据你所提供的值或类型为final变量初始化。然而有时你并不需要这种灵活性,你只需要在定义时便给定其值并永不变化,这时就不要再用这种方法。在main方法中有两行语句注释掉了,如果你去掉注释,程序便无法通过编译,这便是说,不论是i的值或是list的类型,一旦初始化,确实无法再更改。然而b可以通过重新初始化来指定i的值或 list的类型,输出结果中显示了这一点:
I=100 List Type:class java.util.LinkedList
I=23 List Type:class java.util.ArrayList
还有一种用法是定义方法中的参数为final
对于基本类型的变量,这样做并没有什么实际意义,因为基本类型的变量在调用方法时是传递字面值变量的副本值的,也就是说你可以在方法中更改这个参数变量而不会影响到调用语句,然而对于对象变量,却显得很实用,因为对象变量在传递时是传递其引用的副本值,这样你在方法中对对象变量的修改也会影响到调用语句中的对象变量(不是对象),当你在方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法。
另外方法中的内部类在用到方法中的参变量时,此参变也必须声明为final才可使用,如下代码所示:
1. public class INClass{ 2. void innerClass(final String str){ final String abc 3. class IClass{ 4. IClass(){ 5. System.out.println(str); System.out.println(abc); 6. } 7. } 8. IClass ic=new IClass(); 9. } 10. public static void main(String[] args){ 11. INClass inc=new INClass(); 12. inc.innerClass("Hello"); 13. } 14. }
2. 方法不可重写
它表示这个方法不可以被 子类重写,但是它这不影响它被子类继承。同时也不影响重载 。
3. 类不可被继承
最后我们再来回顾一下final用于类的情况。 这个大家应该也很熟悉了, 因为我们最常用的String类就是final 的。由于final类不允许被继承,编译器在处理时把它的所有方法都当作final的,因此final类比普通类拥 有更高的效率。而由关键字abstract定义的抽象类含有必须由继承自它的子类重载实现的抽象方法,因此无法同时用final和abstract来修饰同一个类。同样的道理,final也不能用来修 饰接口。
final的类的所有方法都不能被重写,但这并不表示final的类的属性(变量)值也是不可改变的,要想做到final类的属性值不可改变,必须给它增加final修饰
Finally
finally是对Java 异常处理模型的最佳补充。 finally 结构使代码总会执行, 而不管有无异 常发生。使用 finally 可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接 这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。
Finally 使用注意1
Java代码 public final class FinallyTest { // 测试return语句 结果显示:编译器在编译return new ReturnClass();时,将它分成了两个步骤,new ReturnClass()和return,前一个创建对象的语句是在finally语句块之前被执行的,而后一个return语 句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的 public ReturnClass testReturn() { try { return new ReturnClass(); } catch (Exception e) { e.printStackTrace(); } finally{ System.out.println("执行了finally语句"); } return null; }
class ReturnClass {
public ReturnClass() {
System.out.println("执行了return语句");
}
上面这段代码的运行结果如下:
1. 执行了return语句
2. 执行了finally语句
很明显,return、continue和break都没能阻止finally语句块的执行。从输出的结果来看, return语句似乎在 finally语句块之前执行了,事实真的如此吗?
我们来想想看,return语句 的作用是什么呢?是退出当前的方法,并将值或对象返回。如果 finally语句块是在return语 句之后执行的,那么return语句被执行后就已经退出当前方法了,finally语句块又如何能被 执行呢?
因此,正确的执行顺序应该是这样的:编译器在编译return new ReturnClass();时, 将它分成了两个步骤,new ReturnClass()和return,前一个创建对象的语句是在finally语句块 之前被执行的,而后一个return语句是在finally语句块之后执行的,也就是说finally语句块 是在程序退出方法之前被执行的。同样,finally语句块是在循环被跳过(continue)和中断 (break)之前被执行的。
Finally 使用注意2
public static void Test(string fileName) { string fileName; System.IO.StreamReader sr=null; try { sr=new System.IO.StreamReader(fileName); } finally { sr.Close();//可能会出错 //正确写法 /** if(sr!=null) { sr.Close(); } */ } }