总体区别

final       用于申明属性,方法和类,表示属性不可变,方法不可以被覆盖,类不可以被继承。
finally     是异常处理语句结构中,表示总是执行的部分。  
finallize   表示是object类一个方法,在垃圾回收机制中执行的时候会被调用被回收对象的方法。允许回收此前未回收的内存垃圾。所有object都继承了                                   finalize()方法

一.final详解

Java中final也用来修饰3类东西:变量,方法和类。
1.变量
final修饰变量表示该变量是不可变的。例如 final int i =1;在程序中i的值就不允许改变了。比较容易混淆的是final用来修饰引用变量时,表示该引用变量是不可变的即引用变量指向的内存地址是不变的,但是被指的内存地址中的类是可以改变的。例如:
final MyClass myClass = new MyClass();
这样声明myClass后,其所指向的内存地址就固定了,但仍然可以改变myClass所引用对象的成员变量。如果试图重用myClass这个变量,让其引用另一个对象则会出错。
myClass = new MyClass();//error!!!
2.方法
final修饰方法时表示该方法是不能被子类重写的。
3.类

final修饰类时表示该类是不能被继承的,由于java的单继承关系,所以该类是继承关系链中的终端。

关于final的几个注意事项:

a、final变量必须在声明的时候初始化或是在构造函数中初始化;
b、接口中声明的所有变量都是final的;
c、final,finally,finalize的区别。final表示不可变,final表示必须执行的语句,finalize表示垃圾回收时执行的代码。

二.finalize

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

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()的工作就是回收这部分的内存。

三.finally 详解

Java异常处理模型与其他语言相比,关键词finally是最出色的新增特性了。finally构件使得该区段中的代码总是得以执行,而无论是否发生异常,特别适用于维护对象的内部状态(用来保证异常发生恢复对象的有效状态,以确保程序能在处理完异常后自动再次投入运行)和清理non-memory资源(垃圾回收机制无法处理的资源,如数据库连接、Socket等等)。

但有一点值得注意,那就是尽量不要从try区段中返回(调用return),因为只要有finally区段存在,它就一定会被执行,那么如果你在finally区段中又调用了一次return语句,则try区段中的返回值将会被遮掩,使得方法调用者得到的是finally区段中的返回值--这常常又与程序编写的初衷相背。

问题分析

首先来问大家一个问题:finally 语句块一定会执行吗?

很多人都认为 finally 语句块是肯定要执行的,其中也包括一些很有经验的 Java 程序员。可惜并不像大多人所认为的那样,对于这个问题,答案当然是否定的,我们先来看下面这个例子。

清单 1.
public class Test {
public static void main(String[] args) {
System.out.println("return value of test(): " + test());
} public static int test() {
int i = 1; // if(i == 1)
// return 0;
System.out.println("the previous statement of try block");
i = i / 0; try {
System.out.println("try block");
return i;
}finally {
System.out.println("finally block");
}
}
}

清单 1 的执行结果如下:

the previous statement of try block
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.bj.charlie.Test.test(Test.java:15)
at com.bj.charlie.Test.main(Test.java:6)

另外,如果去掉上例中被注释的两条语句前的注释符,执行结果则是:

 return value of test(): 0

在以上两种情况下,finally 语句块都没有执行,说明什么问题呢?只有与 finally 相对应的 try 语句块得到执行的情况下,finally 语句块才会执行。以上两种情况,都是在 try 语句块之前返回(return)或者抛出异常,所以 try 对应的 finally 语句块没有执行。

那好,即使与 finally 相对应的 try 语句块得到执行的情况下,finally 语句块一定会执行吗?不好意思,这次可能又让大家失望了,答案仍然是否定的。请看下面这个例子(清单 2)。

清单 2.
public class Test {
public static void main(String[] args) {
System.out.println("return value of test(): " + test());
} public static int test() {
int i = 1; try {
System.out.println("try block");
System.exit(0);
return i;
}finally {
System.out.println("finally block");
}
}
}

清单 2 的执行结果如下:

try block

finally 语句块还是没有执行,为什么呢?因为我们在 try 语句块中执行了 System.exit (0) 语句,终止了 Java 虚拟机的运行。那有人说了,在一般的 Java 应用中基本上是不会调用这个 System.exit(0) 方法的。OK !没有问题,我们不调用 System.exit(0) 这个方法,那么 finally 语句块就一定会执行吗?

再一次让大家失望了,答案还是否定的。当一个线程在执行 try 语句块或者 catch 语句块时被打断(interrupted)或者被终止(killed),与其相对应的 finally 语句块可能不会执行。还有更极端的情况,就是在线程运行 try 语句块或者 catch 语句块时,突然死机或者断电,finally 语句块肯定不会执行了。可能有人认为死机、断电这些理由有些强词夺理,没有关系,我们只是为了说明这个问题。

下面,我们先来看一个简单的例子(清单 3)。

清单 3.
public class Test {
public static void main(String[] args) {
try {
System.out.println("try block"); return ;
} finally {
System.out.println("finally block");
}
}
}

清单 3 的执行结果为:

try block
finally block

清单 3 说明 finally 语句块在 try 语句块中的 return 语句之前执行。我们再来看另一个例子(清单 4)。

清单 4.
public class Test {
public static void main(String[] args) {
System.out.println("reture value of test() : " + test());
} public static int test(){
int i = 1; try {
System.out.println("try block");
i = 1 / 0;
return 1;
}catch (Exception e){
System.out.println("exception block");
return 2;
}finally {
System.out.println("finally block");
}
}
}

清单 4 的执行结果为:

try block
exception block
finally block
reture value of test() : 2

清单 4 说明了 finally 语句块在 catch 语句块中的 return 语句之前执行。

从上面的清单 3 和清单 4,我们可以看出,其实 finally 语句块是在 try 或者 catch 中的 return 语句之前执行的。更加一般的说法是,finally 语句块应该是在控制转移语句之前执行,控制转移语句除了 return 外,还有 break 和 continue。另外,throw 语句也属于控制转移语句。虽然 return、throw、break 和 continue 都是控制转移语句,但是它们之间是有区别的。其中 return 和 throw 把程序控制权转交给它们的调用者(invoker),而 break 和 continue 的控制权是在当前方法内转移。请大家先记住它们的区别,在后续的分析中我们还会谈到。

还是得来点有说服力的证据,下面这段摘自 Java 语言规范第四版(The Java™ Programming Language, Fourth Edition),请读者自己体会一下其含义。

好了,看到这里,是不是有人认为自己已经掌握了 finally 的用法了?先别忙着下结论,我们再来看两个例子 – 清单 5 和清单 6。

清单 5.
public class Test {
public static void main(String[] args) {
System.out.println("return value of getValue(): " + getValue());
} public static int getValue() {
try {
return 0;
} finally {
return 1;
}
}
}

清单 5 的执行结果:

return value of getValue(): 1
清单 6.
public class Test {
public static void main(String[] args) {
System.out.println("return value of getValue(): " + getValue());
} public static int getValue() {
int i = 1;
try {
return i;
} finally {
i++;
}
}
}

清单 6 的执行结果:

return value of getValue(): 1

利用我们上面分析得出的结论:finally 语句块是在 try 或者 catch 中的 return 语句之前执行的。 由此,可以轻松的理解清单 5 的执行结果是 1。因为 finally 中的 return 1;语句要在 try 中的 return 0;语句之前执行,那么 finally 中的 return 1;语句执行后,把程序的控制权转交给了它的调用者 main()函数,并且返回值为 1。那为什么清单 6 的返回值不是 2,而是 1 呢?按照清单 5 的分析逻辑,finally 中的 i++;语句应该在 try 中的 return i;之前执行啊? i 的初始值为 1,那么执行 i++;之后为 2,再执行 return i;那不就应该是 2 吗?怎么变成 1 了呢?

关于 Java 虚拟机是如何编译 finally 语句块的问题,有兴趣的读者可以参考《 The JavaTM Virtual Machine Specification, Second Edition 》中 7.13 节 Compiling finally。那里详细介绍了 Java 虚拟机是如何编译 finally 语句块。实际上,Java 虚拟机会把 finally 语句块作为 subroutine(对于这个 subroutine 不知该如何翻译为好,干脆就不翻译了,免得产生歧义和误解。)直接插入到 try 语句块或者 catch 语句块的控制转移语句之前。但是,还有另外一个不可忽视的因素,那就是在执行 subroutine(也就是 finally 语句块)之前,try 或者 catch 语句块会保留其返回值到本地变量表(Local Variable Table)中。待 subroutine 执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过 return 或者 throw 语句将其返回给该方法的调用者(invoker)。请注意,前文中我们曾经提到过 return、throw 和 break、continue 的区别,对于这条规则(保留返回值),只适用于 return 和 throw 语句,不适用于 break 和 continue 语句,因为它们根本就没有返回值。

转自:http://www.ibm.com/developerworks/cn/java/j-lo-finally/

【Java面试题】19 final,finally和finalize的区别的更多相关文章

  1. 异常-面试题之final,finally和finalize的区别,如果在finally之前有return

    package cn.itcast_07; /* * 面试题: * 1:final,finally和finalize的区别 * final:最终的意思,可以修饰类,成员变量,成员方法 * 修饰类,类不 ...

  2. final,finally和finalize的区别

    package com.heima.test; public class Test1 {  /**  * * A:面试题1   * final,finally和finalize的区别   * fina ...

  3. Java面试题之final、finally和finalize的区别

    final: final是一个修饰符,可以修饰变量.方法和类,如果final修饰变量,意味着变量的值在初始化后不能被改变: 防止编译器把final域重排序到构造函数外:(面试的时候估计答出这个估计会加 ...

  4. java面试题之final、finalize和finally的区别

    finally:finally是一个关键字,与try和catch一起用于异常的处理,finally块一定会执行,无论在try快中是否有发生异常. finalize:finalize方法是在对象被回收之 ...

  5. final, finally 和finalize的区别

    final 修饰符(关键字) 如果一个类被声明为final,意味着它不能再派生新的子类,不能作为父类被继承.因此一个类不能及被声明为abstract,又被声明为final的.将变量或方法声明为fina ...

  6. 【Java面试题】38 Collection 和 Collections的区别

    Collection是集合类的一个顶级接口,其直接继承接口有List与Set 而Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序.搜索以及线程安 ...

  7. 【Java面试题】33 HashMap和Hashtable的区别

    1 HashMap不是线程安全的 hastmap是一个接口 是map接口的子接口,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值.HashMap允许null key和n ...

  8. 【Java面试题】32 ArrayList和Vector的区别

    1. Vector & ArrayList  相同点: 1.ArrayList和Vector都是继承了相同的父类和实现了相同的接口 2.底层都是数组实现的 3.初始默认长度都为10. 不同点: ...

  9. java面试题之synchronized和lock有什么区别

    synchronized和lock的区别: 类别 synchronized lock 存在层次 java的关键字,在jvm层面上 是一个类 锁的释放 1.以获取锁的线程执行完同步代码,释放锁 2.线程 ...

  10. Java面试题:==运算符与equals方法的区别

    据说这个面试题目,80%的程序员都会理直气壮的回答错误!! 一: ==运算符 如果比较的是基本数据类型,则直接比较数值是否相等,返回值为"true or false" 如果比较的是 ...

随机推荐

  1. macOS 安装 Java (Homebrew)

    macOS 安装多个 Java 版本 Homebrew 是 macOS 下的一个非常好用的包管理工具, caskroom 则是基于 Homebrew 构建的一个强大的应用程序管理器. Homebrew ...

  2. Chinese word segment based on character representation learning 论文笔记

    论文名和编号 摘要/引言 相关背景和工作 论文方法/模型 实验(数据集)及 分析(一些具体数据) 未来工作/不足 是否有源码 问题 原因 解决思路 优势 基于表示学习的中文分词 编号:1001-908 ...

  3. Vue学习之路2-项目初搭建

    1.检查环境是否全部安装成功 2.创建项目 2.1.打开dos命令窗口,使用dos命令转到项目文件夹下: 2.2.输入创建项目命令:vue init webpack myproject1 创建不同的打 ...

  4. 【Python 23】52周存钱挑战3.0(循环计数for与range)

    1.案例描述 按照52周存钱法,存钱人必须在一年52周内,每周递存10元.例如,第一周存10元,第二周存20元,第三周存30元,直到第52周存520元. 记录52周后能存多少钱?即10+20+30+. ...

  5. 理论篇-Java中一些零碎的知识点

    1. Java中length,length方法,size方法区别 length属性:用于获取数组长度. length方法:用于获取字符串长度. size方法:用于获取泛型集合有多少个元素. 2. is ...

  6. python之shutil

    ''' shutil 用来处理 文件 文件夹 压缩包 的模块 ''' import shutil # 拷贝文件内容 shutil.copyfileobj(open('old.xml', 'r'), o ...

  7. .net core EF的简单使用

    1.在mysql中新建一个表 2.在控制台中装个EF包  Install-Package Pomelo.EntityFrameworkCore.MySql 3.新建一个Person类 4.创建DbCo ...

  8. GRE与VXLAN

    一 GRE 1.1 概念 GRE全称是Generic Routing Encapsulation,是一种协议封装的格式,具体格式内容见:https://tools.ietf.org/html/rfc2 ...

  9. 你不知道的 requestIdleCallback

    本文副标题是 Request Schedule 源码解析一.在本章中会介绍 requestIdleCallback 的用法以及其缺陷, 接着对 React 团队对该 api 的 hack 部分的源码进 ...

  10. day02(编程语言,解释器,环境变量,执行方式,pycharm,pip,变量三大组成)

      上节课复习: 重点: 1,进制转换:二进制与十六进制 2,内存分布:栈区 与 堆区 10101001110111 => 2a77 abf1 => 1010101111110001 计算 ...