JAVA学习笔记--final、finally、finalize的区别

来源:互联网 发布:cc2541中文数据手册 编辑:程序博客网 时间:2024/05/01 03:06


final:

        java中的关键字,修饰符。用于声明属性,方法和类,分别表示属性不可改变,方法不可覆盖,类不可继承。

1. 定义变量,包括静态的和非静态的。     

2. 定义方法的参数。     

3. 定义方法。     

4. 定义类。


(1)定义变量,包括静态的和非静态的

1.1 如果final修饰的是一个基本类型,要求变量初始化必须在声明时或者构造函数中,不能用于其它地方。该关键字定义的常量,除了初始化阶段,不能更改常量的值。final标识的关键字存储在常量池中。

一种更贴切的表述final的含义的描述:如果一个变量或方法参数被final修饰,就表示它只能被赋值一次,但是JAVA虚拟机为变量设定的默认值不记作一次赋值。被final修饰的变量必须被初始化

初始化的方式有以下几种:     

1. 在定义的时候初始化。     

2. final变量可以在初始化块中初始化,不可以在静态初始化块中初始化。     

3. 静态final变量可以在静态初始化块中初始化,不可以在初始化块中初始化。     

4. final变量还可以在类的构造器中初始化,但是静态final变量不可以。

[java] view plain copy print?
  1.        // 在定义时初始化  
  2. public final int A = 10;  
  3.   
  4. // 在初始化块中初始化  
  5. public final int B;  
  6. {  
  7.     B = 20;  
  8. }  
  9. // 非静态final变量不能在静态初始化块中初始化  
  10. // public final int C;  
  11. // static {  
  12. // C = 30;  
  13. // }  
  14.   
  15. // 静态常量,在定义时初始化  
  16. public static final int STATIC_D = 40;  
  17.   
  18. // 静态常量,在静态初始化块中初始化  
  19. public static final int STATIC_E;  
  20. static {  
  21.     STATIC_E = 50;  
  22. }  
  23.   
  24. // 静态变量不能在初始化块中初始化  
  25. // public static final int STATIC_F;  
  26. // {  
  27. // STATIC_F = 60;  
  28. // }  
  29.   
  30. public final int G;  
  31. // 静态final变量不可以在构造器中初始化  
  32. //public static final int STATIC_H;  
  33.   
  34. // 在构造器中初始化  
  35. public test() {  
  36.     G = 70;  
  37.     // 静态final变量不可以在构造器中初始化  
  38.     //STATIC_H = 80;  
  39.   
  40.     // 给final的变量第二次赋值时,编译会报错  
  41.     //A = 99;  
  42.     //STATIC_D = 99;  
  43.   
  44.     // final变量未被初始化,编译时就会报错  
  45.     //public final int I;  
  46.     // 静态final变量未被初始化,编译时就会报错  
  47.     //public static final int STATIC_J;  
  48. }  
注:final int i //可在编译时初始化或是运行时初始化

        static final int i //只能在编译时初始化
用final修饰的变量(常量)比非final的变量(普通变量)拥有更高的效率,因此我们在际编程中应该尽可能多的用常量来代替普通变量,这也是一个很好的编程习惯。


1.2 如果final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的。这里需要提醒大家注意的是,不可改变的只是这个变量所保存的引用,并不是这个引用所指向的对象。


(2)定义方法的参数。

1.1  定义基本数据类型的参数     

可以读参数,但是无法改变参数。主要用来向匿名内部类传递数据。

1.2  定义引用类型的参数

无法在方法中更改参数引用所指向的对象。


(3)定义方法。

表示这个方法不可以被子类重写(覆盖),但是它这不影响它被子类继承

[java] view plain copy print?
  1. public class ParentClass {  
  2.     public final void TestFinal() {  
  3.         System.out.println("父类--这是一个final方法");  
  4.     }  
  5. }  
  6.   
  7. public class SubClass extends ParentClass {  
  8.     /** * 子类无法重写(override)父类的final方法,否则编译时会报错 */  
  9.     // public void TestFinal()  
  10.     // { System.out.println("子类--重写final方法");  
  11.     // }  
  12.     public static void main(String[] args) {  
  13.         SubClass sc = new SubClass();  
  14.         sc.TestFinal();  
  15.     }  
  16. }  
这里需要特殊说明的是,具有private访问权限的方法也可以增加final修饰,但是由于子无法继承private方法,因此也无法重写它。编译器在处理private方法时,是按照final方来对待的,这样可以提高该方法被调用时的效率。不过子类仍然可以定义同父类中private方法具有同样结构的方法,但是这并不会产生重写的效果,而且它们之间也不存在必然联系。

使用final方法的原因有二:
第一、把方法锁定,防止任何继承类修改它的意义和实现。
第二、高效。编译器在遇到调用final方法时候会转入内嵌机制,大大提高执行效率。   


(4)定义类。

1.final修饰的类是不可以被继承的。final类不可被继承,final的所有方法都默认为final。我们最常用的String类就是final的

2.由于final类不允许被继承,编译器在处理时把它的所有方法都当作final的,因此final类比普通类拥有更高的效率。

3.由关键字abstract定义的抽象类含有必须由继承自它的子类重载实现的抽象方法,因此无法同时用final和abstract来修饰同一个类。同样的道理,final也不能用来修饰接口。 

final的类的所有方法都不能被重写,但这并不表示final的类的属性(变量)值也是不可改变的,要想做到final类的属性值不可改变,必须给它增加final修饰,

[java] view plain copy print?
  1. public final class FinalTest {  
  2.     int i = 10;  
  3.     final int j = 50;  
  4.   
  5.     public static void main(String[] args) {  
  6.         FinalTest ft = new FinalTest();  
  7.         ft.i = 99// final类FinalTest的属性值 i是可以改变的,因为属性值i前面没有final修//  
  8.         // ft.j = 49; // 报错....因为 j 属性是final 的不可以改变。  
  9.         System.out.println(ft.i);  
  10.     }  
  11. }  


finally:

        finally是异常处理语句结构的一部分,只能用在try/catch语句中并且附带着一个语句块,表示这段语句最终总是被执行。java的一种异常处理机制。finally是对Java 异常处理模型的最佳补充。finally 结构使代码总会执行,而不管有无异常发生。使用 finally 可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。

return、continue、break这三个可以打乱代码顺序执行语句的规律。

[java] view plain copy print?
  1. public class FinallyTest {    
  2.         
  3.     // 测试return语句    
  4.     public ReturnClass testReturn() {    
  5.         try {    
  6.             return new ReturnClass();    
  7.         } catch (Exception e) {    
  8.             e.printStackTrace();    
  9.         } finally {    
  10.             System.out.println("执行了finally语句");    
  11.         }    
  12.         return null;    
  13.     }    
  14.     
  15.     // 测试continue语句    
  16.     public void testContinue() {    
  17.         for (int i = 0; i < 3; i++) {    
  18.             try {    
  19.                 System.out.println(i);    
  20.                 if (i == 1) {    
  21.                     continue;    
  22.                 }    
  23.             } catch (Exception e) {    
  24.                 e.printStackTrace();    
  25.             } finally {    
  26.                 System.out.println("执行了finally语句");    
  27.             }    
  28.         }    
  29.     }    
  30.     
  31.     // 测试break语句    
  32.     public void testBreak() {    
  33.         for (int i = 0; i < 3; i++) {    
  34.             try {    
  35.                 System.out.println(i);    
  36.                 if (i == 1) {    
  37.                     break;    
  38.                 }    
  39.             } catch (Exception e) {    
  40.                 e.printStackTrace();    
  41.             } finally {    
  42.                 System.out.println("执行了finally语句");    
  43.             }    
  44.         }    
  45.     }    
  46.     
  47.     public static void main(String[] args) {    
  48.         FinallyTest ft = new FinallyTest();    
  49.         // 测试return语句    
  50.         ft.testReturn();    
  51.         System.out.println();    
  52.         // 测试continue语句    
  53.         ft.testContinue();    
  54.         System.out.println();    
  55.         // 测试break语句    
  56.         ft.testBreak();    
  57.     }    
  58. }    
  59.     
  60.  class ReturnClass {    
  61.     public ReturnClass() {    
  62.         System.out.println("执行了return语句");    
  63.     }    
  64. }  
结果:

执行了return语句
执行了finally语句


0
执行了finally语句
1
执行了finally语句
2
执行了finally语句


0
执行了finally语句
1
执行了finally语句

编译器在编译return new ReturnClass();时,将它分成了两个步骤,new ReturnClass()和return,前一个创建对象的语句是在finally语句块之前被执行的,而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的。同样,finally语句块是在循环被跳过(continue)和中断(break)之前被执行的。


finally中存在return语句的情况:

[java] view plain copy print?
  1. public int test() {  
  2.         try {  
  3.             System.out.println("try");  
  4.             return 1;  
  5.         } catch (Exception e) {  
  6.             System.out.println("catch");  
  7.             return 2;  
  8.         } finally {  
  9.             System.out.println("finally");  
  10.             return 3;  
  11.         }  
  12.   
  13.     }  
输出结果:(Eclipse会给出警告,但能编译运行)

try

finally
3


当finall块中包含return语句时,Eclipse会给出警告“finally block does not complete normally”,原因分析如下:
1、不管try块、catch块中是否有return语句,finally块都会执行。
2、finally块中的return语句会覆盖前面的return语句(try块、catch块中的return语句),所以如果finally块中有return语句,Eclipse编译器会报警告“finally block does not complete normally”。
3、如果finally块中包含了return语句,即使前面的catch块重新抛出了异常,则调用该方法的语句也不会获得catch块重新抛出的异常,而是会得到finally块的返回值,并且不会捕获异常。
结论:
finally 内部使用 return 语句是一种很不好的习惯,如果try中还有return语句,它会覆盖了try 区域中 return 语句的返回值,程序的可读性差


finalize:

        它是一个方法,Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。属于java.lang.Object类,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。注意:finalize不一定被jvm调用,只有当垃圾回收器要清除垃圾时才被调用。

它的定义如下:

[java] view plain copy print?
  1. protected void finalize() throws Throwable { }  

众所周知,finalize()方法是GC(garbage collector)运行机制的一部分。finalize()方法的作用是什么呢?finalize()方法是在GC清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异常(uncaught exception),GC将终止对改对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。

[java] view plain copy print?
  1. public final class FinallyTest {  
  2.     // 重写finalize()方法  
  3.     protected void finalize() throws Throwable {  
  4.         System.out.println("执行了finalize()方法");  
  5.     }  
  6.   
  7.     public static void main(String[] args) {  
  8.         FinallyTest ft = new FinallyTest();  
  9.         ft = null;  
  10.         System.gc();  
  11.     }  
  12. }  
运行结果如下: 执行了finalize()方法


程序调用了java.lang.System类的gc()方法,引起GC的执行,GC在清理ft对象时调用了它的finalize()方法,因此才有了上面的输出结果。调用System.gc()等同于调用下面这行代码:Runtime.getRuntime().gc();调用它们的作用只是建议垃圾收集器(GC)启动,清理无用的对象释放内存空间,但是GC的启动并不是一定的,这由JAVA虚拟机来决定。直到 JAVA虚拟机停止运行,有些对象的finalize()可能都没有被运行过,那么怎样保证所有对象的这个方法在JAVA虚拟机停止运行之前一定被调用呢?答案是我们可以调用System类的另一个方法:public static void runFinalizersOnExit(boolean value) {//other code}    给这个方法传入true就可以保证对象的finalize()方法在JAVA虚拟机停止运行前一定被运行了,不过遗憾的是这个方法是不安全的,它会导致有用的对象finalize()被误调用,因此已不被赞成使用了。 



final、finally、finalize的简单区别 
一、性质不同
(1)final为关键字;
(2)finalize()为方法;
(3)finally为为区块标志,用于try语句中;

二、作用
(1)final为用于标识常量的关键字,final标识的关键字存储在常量池中;

(2)finally{}用于标识代码块,与try{}进行配合,不论try中的代码执行完或没有执行完(这里指有异常),该代码块之中的程序必定会进行;

(3)finalize()方法在Object中进行了定义,用于在对象“消失”时,由JVM进行调用用于对对象进行垃圾回收,类似于C++中的析构函数;用户自定义时,用于释放对象占用的资源(比如进行I/0操作);

1 0
原创粉丝点击