Java中final、finally、finalize的区别
1.简单区别
- final用于声明属性,方法和类,分别表示属性不可交变,方法不可覆盖,类不可继承。
- finally是异常处理语句结构的一部分,表示总是执行。
- finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。
2.详细介绍
- final
- final属性:被final修饰的变量不可变,由于变量不可变有两重含义:一是引用不可变;而是对象不可变。final指的是引用的不可变性。举例说明。
public class Test{
public static void main(String [] args){
final StringBuffer s = new StringBuffer("Hello");
s.append(" world");
System.out.println(s);
}
}
运行结果为:Hello world
public class Test{
public static void main(String [] args){
final StringBuffer s = new StringBuffer("Hello");
s=new StringBuffer(" Hello world");
}
}
运行结果为:编译错误
分析:由以上可知final指的是引用不可变性,即它只能指向初始化时指向的的那个对象,而不关心指向对象内容的变化。所以,被final修饰的边浪必须被初始化,初始化方式:
1) 定义的时候初始化;
2) final成员变量可以在初始化快中初始化,但不可在静态初始化块中初始化;
3) 静态final成员变量可以在静态初始化快中初始化,但不可在初始块中初始化;
4) 在类的构造器中初始化,但静态final成员变量不可以在构造函数中初始化。
- final方法 被声明final的方法只能使用,不能重载。该方法不允许任何子类重写这个方法。但子类仍然可以使用这个方法。 final参数:用来表示这个参数在这个函数内部不允许被修改。
- final类 如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承,所有的方法都不能被重写。但这并不代表final类的成员变量也是不可改变的,要想做到final类的成员变量不可变,必须给成员变量增加final修饰。注意:一个类不能同时被声明为absrtact的类和final的类。
- finally:java的一种异常处理机制 finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定被执行,经常被用在需要释放资源的情况下。 示例1:
Connection conn;
Statement stmt;
try{
conn=DriverManager.getConnection(url,userName,password);
stmt=conn.createStatement();
stmt.executeUpdate(update); //执行一条update语句,此时抛出异常
stmt.close();
conn.close();
}catch(Exception e){
}
在上面的程序片段中,如果程序在运行过程中没有发生异常,那么数据库的连接能够得到释放,程序运行没有问题。如果在执行update语句时抛出异常,后面的close()方法将不会被调用,数据库的连接将得不到释放。如果这样的程序长期执行,将会耗光数据库的连接资源。通过使用finally可以保证任何情况下数据库的连接资源都能够释放。
Connection conn;
Statement stmt;
try{
conn=DriverManager.getConnection(url,userName,password);
stmt=conn.createStatement();
stmt.executeUpdate(update); //执行一条update语句,此时抛出异常
stmt.close();
conn.close();
}catch(Exception e) finally{
if(stmt != null)
stmt.close();
if(conn != null)
conn.close();
}
上述代码可以保证不管程序是否发生异常,finally中的代码一定会执行,这样能保证数据库的连接资源都能被释放。
- finalized finalized是java.lang.Object类的一个方法,它的定义如下:
//Java代码
protected void finalize() throws Throwable { }
根据Java语言规范,JVM保证调用finalize函数之前,这个对象是不可达的,但是JVM不保证这个函数一定会被调用。另外,规范还保证finalize函数最多运行一次。
通常,finalize用于一些不容易控制、并且非常重要资源的释放,例如一些I/O的操作,数据的连接。这些资源的释放对整个应用程序是非常关键的。在这种情况下,程序员应该以通过程序本身管理(包括释放)这些资源为主,以finalize函数释放资源方式为辅,形成一种双保险的管理机制,而不应该仅仅依靠finalize来释放资源(原文)。
Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
Java中所有类都从Object类中继承finalize()方法。
当垃圾回收器(garbage colector)决定回收某对象时,就会运行该对象的finalize()方 法。值得C++程序员注意的是,finalize()方法并不能等同与析构函数。Java中是没有析构函数的。C++的析构函数是在对象消亡时运行的。由于C++没有垃圾回收,对象空间手动回收,所以一旦对象用不到时,程序员就应当把它delete()掉。所以析构函数中经常做一些文件保存之类的收尾工作。但是在Java中很不幸,如果内存总是充足的,那么垃圾回收可能永远不会进行,也就是说filalize()可能永远不被执行,显然指望它做收尾工作是靠不住的。
那么finalize()究竟是做什么的呢?它最主要的用途是回收特殊渠道申请的内存。Java程序有垃圾回收器,所以一般情况下内存问题不用程序员操心。但有一种JNI(Java Native Interface)调用non-Java程序(C或C++),finalize()的工作就是回收这部分的内存。
finalize()方法是在GC清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异常(uncaught exception),GC将终止对改对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。请看下面的示例。:
public final class FinallyTest{
//重写finalize()方法
protected void finalize() throws Throwable{
System.out.println("执行了finalize()方法");
}
public static void main(String[] args){
FinallyTest ft = new FinallyTest();
ft = null;
System.gc();
}
}
运行结果如下:执行了finalize()方法
程序调用了java.lang.System类的gc()方法,引起GC的执行,GC在清理ft对象时调用了它的finalize()方法,因此才了上面的输出结果。调用System.gc()等同于调用下面这行代码:
Runtime.getRuntime().gc();
调用它们的作用只是建议垃圾收集器(GC启动,清理无用的对象释放内存空间,但是GC的启动并不是一定的,这由JAVA虚拟机来决定。直到 JAVA虚拟机停止运行, 一些对象的finalize()可能都没被运行过,那么怎样保证所有对象的这个方法在JAVA虚拟机停止运行之前一定被调用呢?答案是我们可以调用System类的另一个方法:
public static void FunFinalizersOnExit(boolean value){
//othercode
}
给这个方法传入true就可以保证对象的finalize()方法在JAVA虚拟机停止运行前一定被运行了,不过遗憾的是这个方法是不安全的,它会导致有用的对象finalize()被误调用,因此已不被赞成使用了。由于finalize()属于Object类,因此所类都这个方法,Object的任意子类都可以重写(override该方法,在其中释放系统资源或者做其它的清理工作,如关闭输入输出流。