一、概述
final是JAVA關鍵字中最常見之一,表示“最終的,不可更改”之意,在Java中也正是這個意思。
有final修飾的內(nèi)容,就會變得與眾不同,它們會變成終極存在,其內(nèi)容成為固定的存在。
finally關鍵字不同于final關鍵字,這是一個需要與異常體系結構配合使用的關鍵字,旨在定義必須要進行操作,一般用于在發(fā)生異常的時候進行一些收尾操作,比如釋放資源等。
另外還有個finalized,它是一個方法,它需要與垃圾收集體系配合使用。主要在對象被垃圾收集之前進行一些操作,這些操作只會被執(zhí)行一次,即使一個對象多次被標記為下次進行垃圾收集,也只有第一次會執(zhí)行。
二、final作用
2.1 final修飾變量
變量被final修飾就會變成為常量,常量被保存在方法區(qū)中。
變量一旦被final修飾,必須手動進行初始化,未進行初始化的final常量是無法通過編譯的。
如果只有final修飾的變量的初始化可以采用:
- 定義時賦值
- 代碼塊賦值
- 構造器賦值
如果被static和final同時修飾的變量的初始化可以采用:
- 定義時賦值
- 靜態(tài)代碼塊賦值
一旦final變量被static修飾,那么它就脫離了對象的組織(代碼塊、構造器都是對象的組織),升級為類的組織,所以需要在類級別的靜態(tài)代碼塊中進行初始化。
public class FinalTest {
final int i = 1;
int j = 2;
static int m = 3;
static final int n = 4;
}
或
public class FinalTest {
final int i;
int j;
static int m;
static final int n;
{
i = 1;
}
static {
n = 3;
}
}
如果將上面的代碼改成:
public class FinalTest {
final int i;//2-
int j;
static int m;
static final int n;//5-
}
上面代碼第2行和第5行會報錯,原因就是未進行初始化。
那么我們總結下final和static的現(xiàn)象,用于區(qū)分二者:
- static修飾將內(nèi)容脫離對象成為類成員。
- final修飾將內(nèi)容改造成必須被手動初始化的成員,一旦賦值,不再改變。
注意:同時被final和static修飾的變量成為靜態(tài)常量,類常量,這種類常量在編譯階段會進行常量傳播優(yōu)化,將該類常量的值直接保存到調(diào)用類的常量池中,那么在程序執(zhí)行到調(diào)用位置時,實際上與定義該類常量的類已經(jīng)毫無關系,我(調(diào)用方)可以直接在我的常量池中獲取到編譯階段優(yōu)化過來的值,不再需要通過常量定義類的類型去調(diào)用其中定義的那個類常量了。
二者可以同時存在,各起各的作用。
2.2 final修飾方法
被final修飾的方法,可以被子類繼承,但是不能被子類重寫,也就是說這個方法在此以后其內(nèi)部的實現(xiàn)就是固定不變的了,不能被改變。
2.3 final修飾類
被final修飾的類,被稱之為最終類,其不再擁有子類,不可再進行擴展,最常見的final類就是String類。
String類被final修飾之后,其每個對象都是不變的,一旦定義就不再發(fā)生改變。
2.4 final修飾局部變量
final修飾的局部變量,該變量就不再是保存在棧空間中,而是保存在方法區(qū)中,不會隨方法結束而失效,放大了局部變量的生命周期。
最常使用的地方就是局部內(nèi)部類在訪問方法的局部變量的情況下,這些局部變量就需要使用final修飾,因為當局部內(nèi)部類訪問局部變量時,會放大局部變量的作用域,局部變量一般在方法結束時就失效了,但是卻有可能任然被內(nèi)部類的對象持有使用。將該局部變量定義為final之后,它不再保存于棧空間,而是保存在方法區(qū)中,自然不會因為方法的結束而丟失。
public class FinalTest{
public void outMethod(){
final int s = 1;// 3-
class innerClass{
public void innerMethod(){
System.out.println(s);
}
}
}
}
如果去掉第3行的final,第5行就會報錯。
2.5 final修飾方法參數(shù)
如果方法的參數(shù)被final修飾,那么這個參數(shù)的值在從方法調(diào)用時賦值開始就不能再改變,不能被重新賦值(不能改成他值)。
public class FinalTest{
public void outMethod(final int s){
s = 1;
}
}
如上代碼,方法參數(shù)s為final的,那么若去掉第2行的代碼,為s重新賦值,則會報錯。
三、finally作用
finally只有一種用法,那就是在try...catch..語句末尾使用。語法如下:
public class FinallyTest{
public void test(){
try{
//someExecute
}catch(Exception e){
//someExecute
}finally{
//someExecute
}
}
}
finally塊中的語句是一定會被執(zhí)行的,無論是否會發(fā)生異常,重點:這里的異常指的是在try塊中的部分,如果實在try塊之前發(fā)生了異常,還沒來得及執(zhí)行try塊語句,那么finally塊中的內(nèi)容也不會被執(zhí)行,所以finally針對的是try塊中的內(nèi)容而設的。
如果在try塊或catch塊中存在return語句,那么,finally塊中的內(nèi)容必然會在return之前執(zhí)行。
finally經(jīng)常用于發(fā)生異常的情況下關閉打開的資源,比如io流,網(wǎng)絡資源等。
四、finalized作用
finalized是Object類的protected方法。
當垃圾回收器發(fā)現(xiàn)一個對象不存在任何引用的時候,就會觸發(fā)該方法的調(diào)用,調(diào)用由垃圾回收器發(fā)起。
子類重寫該方法一般用于處理系統(tǒng)資源或者一些清理工作。
該方法并不被確保一定會調(diào)用,但是可以保證的是,一旦被調(diào)用,調(diào)用的線程并不會持有任何的同步鎖,而且如果執(zhí)行發(fā)生了異常,則忽略異常,同時停止執(zhí)行。也就是說,finalized方法并不會對程序的正常流程、代碼的正常運行造成意外的影響。
class FinalizedTest{
@Override
public void finalize(){
// do something
}
}
簡述finalized執(zhí)行流程:
當對象變成(GC Roots)不可達時,GC會判斷該對象是否覆蓋了finalize方法,若未覆蓋,則直接將其回收。否則,若對象未執(zhí)行過finalize方法,將其放入F-Queue隊列,由一低優(yōu)先級線程執(zhí)行該隊列中對象的finalize方法。執(zhí)行finalize方法完畢后,GC會再次判斷該對象是否可達,若不可達,則進行回收,否則,對象“復活”。(摘自參考文章)
參考:
- java finalize方法總結、GC執(zhí)行finalize的過程 - ScaleZ - 博客園