·
其实谈区别是建立在有一点点关联得东西得基础之上去谈论他们得区别,单纯得就Java来说其实他们根本没有什么联系,他们是三个层面得东西final表示最终,用来修饰变量、类以及方法的。finally是try 关键字最后可以定义 finally 代码块。 finally 块中定义的代码,总是在 try 和任何 catch 块之后、方法完成之前运行。正常情况下,不管是否抛出或捕获异常 finally 块都会执行。而finalize是object中的方法表示其在Gc垃圾回收时调用该方法,由于GC的自动回收机制,因而并不能保证finalize方法会被及时地执行(垃圾对象的回收时机具有不确定性),也不能保证它们会被执行(程序由始至终都未触发垃圾回收)。
final
在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)
final被意为最终的,同样在修饰这些与类、变量、方法时,也表示最终的。
在修饰类时表示不能继承,
类中的变量被final修饰将变为常量,即表示对基本数据类型时,该变量的值是无法修改的;如果该变量为引用数据类型时,表示对该引用数据类型的引用是不能改变的,但是对引用中的数据是可以改变的。
如果final修饰方法时该方法不能被重写,即将该方法称为锁定方法,比如写底层算法时不希望上层对象对该方法进行重写即可用final修饰。
当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。
public static void main(String[] args) {
String a = "hello2";//常量池
final String b = "hello"; //常量池
String d = "hello"; //用有的
String c = b + 2; //替换
String e = d + 2;//链接 底层通过 new StringBuilder().append()实现
System.out.println((a == c));//true
System.out.println((a == e)); //false
}
上述代码为什么会输出这样得结果呢?这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。这种和C语言中的宏替换有点像。因此在上面的一段代码中,由于变量b被final修饰,因此会被当做编译器常量,所以在使用到b的地方会直接将变量b 替换为它的 值,而对于变量d的访问却需要在运行时通过链接来进行。
finally
在try 关键字最后可以定义 finally 代码块。 finally 块中定义的代码,总是在 try 和任何 catch 块之后、方法完成之前运行。正常情况下,不管是否抛出或捕获异常 finally 块都会执行。因为这一特性,因此我们可以在 finally 代码块中执行关闭连接、关闭文件和释放线程的的操作。
finally 的执行时机
没有异常执行时机
try {
System.out.println("try 块");
} finally {
System.out.println("finally 块");
}
#执行结果
try 块
finally 块
有异常没有catch 执行时机
try {
System.out.println("try内块");
throw new Exception();
} finally {
System.out.println("finally块");
}
#执行结果
try 块
finally 块
有异常有catch执行时机
try {
System.out.println("try块");
throw new Exception();
} catch (Exception e) {
System.out.println("catch块");
} finally {
System.out.println("finally块");
}
#执行结果
try 块
catch块
finally 块
try内return
try {
System.out.println("try块");
return "from try";
} finally {
System.out.println("finally块");
}
#执行结果
try 块
finally 块
try内有异常catch中return
try {
System.out.println("try 块");
throw new Exception();
} catch (Exception e) {
System.out.println("catch 块");
return "from catch";
} finally {
System.out.println("finally 块");
}
#执行结果
try块
catch块
finally块
什么时候finally中的代码不会执行
- 代码执行根本没有进入try块已经进行了return
- 代码进入try块,但在try内有死循环无法退出try
- 代码进入try块,在执行finally块之前执行了System.exit(0)将虚拟机退出
- 代码进入try块,在执行finally块之前调用了Runtime.getRuntime().halt()进行了前行退出
finalize()方法
finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。
finalize的执行过程
当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。
对象复活
在根搜索中得到的不可达对象并不是立即就被标记成可回收的,而是先进行一次标记放入F-Queue等待执行对象的finalize()方法,执行后GC将进行二次标记,复活的对象之后将不会被回收。因此,使对象复活的唯一办法就是重写finalize()方法,并使对象重新被引用。
class User{
public static User user = null;
@Override
protected void finalize() throws Throwable {
System.out.println("User-->finalize()");
user = this;
}
}
class FinalTest {
public static void main(String[] args) throws InterruptedException {
User user = new User();
user = null;
System.gc();
Thread.sleep(1000);
user = User.user;
System.out.println(user != null);
user = null;
System.gc();
Thread.sleep(1000);
System.out.println(user != null);
}
}