final finalize finally 的区别
一、性质不同(1)final为关键字;
(2)finalize()为方法;
(3)finally为为区块标志,用于try语句中;
二、作用
(1)final为用于标识常量的关键字,final标识的关键字存储在常量池中(在这里final常量的具体用法将在下面进行介绍);
(2)finalize()方法在Object中进行了定义,用于在对象“消失”时,由JVM进行调用,用于对对象进行垃圾回收,类似于C++中的析构函数;用户自定义时,用于释放对象占用的资源(比如进行I/0操作)
(3)finally{}用于标识代码块,与try{}进行配合,不论try中的代码执行完或没有执行完(这里指有异常),该代码块之中的程序必定会进行;
三、详解
final 是一种修饰符(关键字),final具有"不可改变的"含义,它可以修饰非抽象类、非抽象成员方法和变量。如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的(能够被继承,而且可能含有抽象方法),又被声明为final(不能被继承)的。将变量或方法声明为 final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引 用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载
final定义变量问题
3.1.1 final定义基本类型变量时,要求变量初始化必须在声明时或者构造函数中,不能用于其它地方。该关键字定义的常量,除了初始化阶段,不能更改常量的值。
3.1.2 final定义对象的引用,该引用的初始化与定义常量时的要求一致;该关键字定义的对象内容可以改变,但是引用指向的地址不能改变;
final定义参数问题
3.2.1 如果传入该参数定义的变量时,方法不能对该参数内容进行修改,与定义变量的修改规则相同;java方法中传递基本类型时是传值的,java方法对于对象的传递是传参的;归根结底,java中方法的传递是依靠传递“副本”:对于基本类型,首先建立一个Copy,并将传入的值赋值给Copy,然后对Copy进行操作;对于对象类型,首先建立一个引用Copy,并将传入的对象引用赋值给Copy;
如下面所示 final修饰的属性(成员变量)赋值的位置:
非静态的成员变量
1.声明的同时
2.匿名代码块
3.构造器(类中出现的所有构造器)
静态的成员变量
1.声明的同时
2.static代码块
a. final可以修饰静态变量、实例变量、局部变量;
b. final变量都必须显示初始化,否则会导致编译错误;
1) 静态变量,定义变量时进行初始化或者static代码块中赋值;
2) 实例变量,可以在定义变量时,或者在构造方法中进行初始化;
c. final变量只能赋一次值。
eg1:
public class Sample {
private final int var1 = 1;
public Sample() {
var1 = 2; //编译出错,不允许改变var1实例变量的值;
}
public void method(final int param) {
final int var2 = 1;
var2++; //编译出错,不允许改变var2局部常量的值
param++; //编译出错,不允许改变final类型参数的值;
}
}
eg2:
public class Sample {
final int var1; //定义var1实例常量
final int var2 = 0; //定义并初始化var2实例常量
Sample() {
var1 = 1; //初始化var1实例常量
}
Sample(int x) {
var1 = x; //初始化var1实例常量
}
}
3.1.1定义方法
(1)使用final关键字定义的方法,不能被子类继承,某些情况下,出于安全原因,父类不允许子类覆盖某个方法, 此时可以把这个方法声明为final类型。例如在 java.lang.Object类中,getClass()方法为final类型;
(2)允许编译器将所有对此方法的调用转化为inline(行内)行为,即可以将此方法直接复制在调用处,而不是进行例行的方法调用(保存断点、压栈),这样会使程序的效率升高。但是---------如果过多的话,这样会造成代码膨胀,反而会影响效率,所以该方法要慎用。。
(3) final不能用来修饰构造方法,因为"方法覆盖"这一概念仅适用于类的成员方法,而不适用于类的构造方法,父类的构造方法和子类的构造方法之间不存在覆盖关系. 因此用final修饰构造方法是无意义的。父类中用private修饰的方法不能被子类的方法覆盖,因此private类型的方法默认是final类型的。
4.1.1定义类
继承关系的弱点是打破封装,子类能够访问父类的方法,而且能以方法覆盖的方式修改实现细节。在以下情况下,可以考虑把类定义为final类型,使得这个类不能被继承。
. 子类有可能会错误地修改父类的实现细节;
. 出于安全,类的实现细节不允许有任何改动;
. 在创建对象模型时,确信这个类不会再被扩展;
例如JDK中java.lang.String类被定义为final类型;
(二)、finalize详解
finalize 属于方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去 之前做必要的清理工作。
这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它 是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者 执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
属于java.lang.Object类,查看API能够知道它的定义如下:
protected void finalize() throws Throwable { }
finalize()方法是在GC清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异常(uncaught exception),GC将终止对该对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。
请看下面的示例:
package sample;
public class FinalizeTest
{
// 重写finalize()方法
protected void finalize() throws Throwable
{
System.out.println("执行了finalize()方法");
}
public static void main(String[] args)
{
FinalizeTest fl = new FinalizeTest();
fl = null;
System.gc();//调用垃圾回收机制
}
}
运行结果如下:即调用了重写的方法,显示:执行了finalize()方法
Runtime.getRuntime().gc();
调用它们的作用只是建议垃圾收集器(GC)启动,清理无用的对象释放内存空间,但是GC的启动并不是一定的,这由JAVA虚拟机来决定。直到 JAVA虚拟机停止运行,有些对象的finalize()可能都没有被运行过,那么怎样保证所有对象的这个方法在JAVA虚拟机停止运行之前一定被调用呢?答案是我们可以调用System类的另一个方法:
public static void runFinalizersOnExit(boolean value) {
//other code
}
给这个方法传入true就可以保证对象的finalize()方法在JAVA虚拟机停止运行前一定被运行了,不过遗憾的是这个方法是不安全的,它会导致有用的对象finalize()被误调用,因此已经不被赞成使用了。由于finalize()属于Object类,因此所有类都有这个方法,Object的任意子类都可以重写(override)该方法,在其中释放系统资源或者做其它的清理工作,如关闭输入输出流。
(三)、finally详解
finally 在异常处理时提供 finally 块来执行必须进行的操作。finally{}用于标识代码块,与try{}进行配合,不论try中的代码执行完或没有执行完(这里指有异常),该代码块之中的程序必定会进行;如果抛出一个异常,那么相匹配 的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。如果不抛出异常,则会从try块中直接跳转到finally块中。如下面程序段:
(1)有异常时:
package sample;
public class TryCatchFinally
{
//用于输出,定义函数专门用于输出
public static void sop(Object o)
{
System.out.println(o);
}
//定义函数用于表示出错信息
static public int div(int a,int b)
{
int res=0;
try
{
res=a/b;
}
catch(ArithmeticException e)
{
sop("in catch");
}
finally
{
sop("in Finally");
}
return res;
}
//主函数
public static void main(String[] args)
{
sop("Main0:"+div(10,0));
}
}
结果如下所示:
如下代码,不存在异常时
package sample;
public class FinallyTest
{
//用于输出,定义函数专门用于输出
public static void sop(Object o)
{
System.out.println(o);
}
//定义函数用于表示出错信息
static public int div(int a,int b)
{
int res=0;
try
{
res=a/b;
}
catch(ArithmeticException e)
{
sop("in catch");
}
finally
{
sop("in Finally");
}
return res;
}
//主函数
public static void main(String[] args)
{
sop("Main0:"+div(10,2));
}
}
运行结果如下所示:没有执行catch块,但和有异常时一样,同样执行finally块
以上就是三者的区别