浅谈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的域江永大写表示,并且使用下划线分割各个单词)
class Value {
int i =
1;
}
public class FinalData {
final int i1 =
9;
static final int I2 =
99;
public static final int I3 =
39;
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 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.v2.i++;
fd1.v1 =
new Value();
for(
int i =
0; i < fd1.a.length; i++)
fd1.a[i]++;
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 字段现在对每个对象都可以有所不同,同时依然保持其“不变”的本质。下面列出一个例子
class Poppet { }
class BlankFinal {
final int i =
0;
final int j;
final Poppet p;
BlankFinal() {
j =
1;
p =
new Poppet();
}
BlankFinal(
int x) {
j = x;
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";
}
}
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 {
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;
}
}
}
}
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还没有快到耗尽内存的地步,它是不会浪费时间进行垃圾回收的。