浅谈Java中的final,finally以及finalize
本文主要是为那些对Java中final,finally以及finalize不是很熟的学习者一个简单参考,本文章的主要参考书籍《Java编程思想》
- final模块
- finally模块
- finalize模块
final模块
根据上下文环境,Java的关键字final的含义存在着细微的差别,但它通常指的是“这是无法改变的”,原因无非是两种:设计或者效率。
这里主要谈论三个只用到final的方面:数据、方法以及类
final数据
final数据 主要是想编译器告知其指向的数据是恒定不变的,主要的作用是,比如:
1、一个永久不变的编译时常量;
2、一个在运行时被初始化的值,你不希望它改变。
final修饰静态变量
无论 static 还是 final 字段,都只能存储一个数据,而且不得改变。
若随同对象句柄使用 final,而不是基本数据类型,它的含义就稍微让人有点儿迷糊了。对于基本数据类型, final 会将值变成一个常数;
然而,对象本身是可以修改的(简单点说,就是final修饰的那个变量内存储的对象地址不能修改,但是所指向的对象是可以修改的)。
(注:在Java中,根据惯例,及时static优势final的域江永大写表示,并且使用下划线分割各个单词)
/*
*代码来自于《Java编程思想》
*/
class Value {
int i = 1;
}
public class FinalData {
// Can be compile-time constants
final int i1 = 9;
static final int I2 = 99;
// Typical public constant:
public static final int I3 = 39;
// Cannot be compile-time constants:
final int i4 = (int)(Math.random()*20);
static final int i5 = (int)(Math.random()*20);
Value v1 = new Value();
final Value v2 = new Value();
static final Value v3 = new Value();
//! final Value v4; // Pre-Java 1.1 Error:
// no initializer
// Arrays:
final int[] a = { 1, 2, 3, 4, 5, 6 };
public void print(String id) {
System.out.println(
id + ": " + "i4 = " + i4 +
", i5 = " + i5);
}
public static void main(String[] args) {
FinalData fd1 = new FinalData();
//! fd1.i1++; // Error: can't change value
fd1.v2.i++; // Object isn't constant!
fd1.v1 = new Value(); // OK -- not final
for(int i = 0; i < fd1.a.length; i++)
fd1.a[i]++; // Object isn't constant!
//! fd1.v2 = new Value(); // Error: Can't
//! fd1.v3 = new Value(); // change handle
//! fd1.a = new int[3];
fd1.print("fd1");
System.out.println("Creating new FinalData");154
FinalData fd2 = new FinalData();
fd1.print("fd1");
fd2.print("fd2");
}
} ///:~
空白final
允许我们创建“空白 final”,它们属于一些特殊的字段。尽管被声明成 final,但却未得到一个初始值。
然而,对于 final 关键字的各种应用,空白 final 具有最大的灵活性。
举个例子来说,位于类内部的一个 final 字段现在对每个对象都可以有所不同,同时依然保持其“不变”的本质。下面列出一个例子
//: BlankFinal.java(代码来自《Java编程思想》)
// "Blank" final data members
class Poppet { }
class BlankFinal {
final int i = 0; // Initialized final
final int j; // Blank final
final Poppet p; // Blank final handle
// Blank finals MUST be initialized
// in the constructor:
BlankFinal() {
j = 1; // Initialize blank final
p = new Poppet();
}
BlankFinal(int x) {
j = x; // Initialize blank final155
p = new Poppet();
}
public static void main(String[] args) {
BlankFinal bf = new BlankFinal();
}
} ///:~
final参数
Java允许在参数列表中一声明的方式将参数指明为final。这以为这你无法再发放中更改参数引用所指向的对象。
声明举例:int test(final int i)...
final方法
使用final方法的原因有两个:
1、把方法锁定,以防止任何的继承类修改它,也即不允许覆盖。
2、程序执行的效率。将一个方法设成 final 后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。(而不是跳转)
class PersonalLoan{
public final String getName(){
return "personal loan";
}
}
class CheapPersonalLoan extends PersonalLoan{
@Override
public final String getName(){
return "cheap personal loan"; //compilation error: overridden method is final
}
}
final类
如果说整个类都是 final,就表明自己不希望从这个类继承,或者不允许其他任何人采取这种操作。
换言之,出于这样或那样的原因,我们的类肯定不需要进行任何改变;或者出于安全方面的理由,我们不希望进行子类化(子类处理)。
除此以外,我们或许还考虑到执行效率的问题,并想确保涉及这个类各对象的所有行动都要尽可能地有效。
final class FinalClass{...}
public class FinalClassTest extends FinalClass{...}
//error:Cannot extend final class 'FinalClass'
finally模块
与其他语言的模型相比,finally 关键字是对 Java 异常处理模型的最佳补充。finally 结构使代码总会执行,而不管有无异常发生。
(无论一个违例是否在 try 块中发生,我们经常都想执行一些特定的代码,该部分代码可放于finally中。)
使用 finally 可以维护对象的内部状态,并可以清理非内存资源。 如果没有 finally,您的代码就会很费解。
public class HelloFinally {
public static void main(String[] args) {
int count = 0;
while(true) {
try {
// post-increment is zero first time:
if(count++ == 0)
throw new Exception();
System.out.println("No exception");
} catch(Exception e) {
System.out.println("Exception thrown");
} finally {
System.out.println("in finally clause");
if(count == 2) break; // out of "while"
}
}
}
} ///:~
finally用来做什么
在没有“垃圾收集”以及“自动调用破坏器”机制的一种语言中, finally 显得特别重要。
因为程序员可用它担保内存的正确释放—— 无论在 try 块内部发生了什么状况,内存总是会得到释放。
当要把除内存之外的资源恢复到他们的厨师状态是,就要用到finally子句:已经代开的文件或者网络连接。
在return中使用finally
因为finally子句总会被执行,所以在一个方法中,可以从多个点返回,并且可以保证重要的清理工作仍旧要进行。
public class MultipleReturns{
pulic static void test(int i)
{
try{
System.out.println("Point 1");
if(i == 1) return;
System.out.println("Point 2");
if(i == 2) return;
System.out.println("Point 3");
if(i == 3) return;
System.out.println("END");
}finally{
System.out.println("Performing cleanup");
}
}
}
finalize模块
Java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize()。
(1).对象不一定会被回收。
(2).垃圾回收不是析构函数。
(3).垃圾回收只与内存有关。
(4).垃圾回收和finalize()都是靠不住的,只要JVM还没有快到耗尽内存的地步,它是不会浪费时间进行垃圾回收的。