深入Java Final
JAVA關(guān)鍵字final用于修飾數(shù)據(jù)、方法或類,通常意味著“無法改變的”,既數(shù)據(jù)不能改變,方法不能覆蓋,類不能繼承。一般采用final有兩種原因:設(shè)計(jì)和效率。而隨著JAVA版本的更新,一些效率上的問題可以交由編譯器和JVM處理。因此,采用final來解決效率問題就顯得不是那么重要了。
Final修飾符大多運(yùn)用于基本數(shù)據(jù)類型(primitive)域或者不可變(immutable)類的域(如果類中的所有方法方法都不會(huì)改變其對(duì)象,這種類就是不可變類。String就是一個(gè)不可變類)。
【final數(shù)據(jù)】
Final關(guān)鍵字用修飾數(shù)據(jù)主要有兩種情況:
1. 編譯期常量
2. 運(yùn)行時(shí)初始化的值
對(duì)于編譯期常量,指的是一個(gè)既是final又是static的域(依照慣例,編譯期常量全部用大寫字母命名,并且用下劃線分隔各個(gè)單詞),它只占據(jù)一段不能改變的存儲(chǔ)空間。編譯器可以將編譯期常量代入到任何可能用到它的計(jì)算式中,也就是說,可以在編譯時(shí)執(zhí)行計(jì)算式,這相對(duì)減輕了運(yùn)行時(shí)負(fù)擔(dān)。編譯期常量在定義時(shí)必須對(duì)它賦值(不一定是基本類型)。
運(yùn)行時(shí)初始化的值,對(duì)于基本類型,final使得其值不可改變;而對(duì)于對(duì)象引用,final使得引用不可改變,即無法將其改為指向另一個(gè)對(duì)象,然而,對(duì)象本身卻可以修改(適用于數(shù)組,數(shù)組也是對(duì)象)。
public class javaFinalData{
private static final String TESTD = "test";
public static final String TESTE = "test";
public static final String[] TESTF = {"1","2"}; //非基本類型
private static final String[] TESTG = new String[2];
public static void main(String args[]){
final int testA = 1;
final String testB = "test";
final int[] testC = {1,1,2,};
System.out.println(testC[1]);
testC[1] = 123;
System.out.println(testC[1]);
}
}
【未賦值的final域】
JAVA允許生成未賦值的final域,但是必須在域的定義處或者每個(gè)構(gòu)造器中對(duì)final域進(jìn)行賦值(有多少個(gè)構(gòu)造器就必須賦值幾次),確保在使用前被初始化。采用這種方式,可以使得final運(yùn)用得更加靈活,在同一個(gè)類中,根據(jù)不同的對(duì)象賦予不同的值,卻又保持不可改變的特性。
public class javaBlankFinal{
private final int blank;
public javaBlankFinal(){
blank = 2011;
}
public javaBlankFinal(int temp){
blank = 2012;
}
public javaBlankFinal(String temp){
blank = 2014;
}
public static void main(String args[]){
new javaBlankFinal();
}
}
【final方法】
使用final方法有兩方面原因:一是將方法鎖定,防止方法被覆蓋,確保在繼承中方法行為保持不變;二是將方法調(diào)用轉(zhuǎn)為內(nèi)聯(lián)調(diào)用(inlining),以減少方法調(diào)用的開銷。但是,在最近的版本中,JVM可以自行進(jìn)行優(yōu)化,因此無需使用final方法來處理效率問題。
關(guān)于final方法,還有一點(diǎn)需要注意,類中所有的private方法都隱式地指定為final方法(也可以為其加上final修飾,但沒有意義)。當(dāng)你試圖覆蓋一個(gè)private方法,編譯器并沒有報(bào)錯(cuò),但是,實(shí)際上你并沒有覆蓋該方法,只是生成了一個(gè)新方法。因?yàn)閜rivate方法是無法被外部類所訪問的,當(dāng)然就無法覆蓋到它了。
使用@Override注解可以防止上述問題。如程序所示:
class finalFunction{
private void finalFunctionA(){
System.out.println("finalFunctionA");
}
private final void finalFunctionB(){
System.out.println("finalFunctionB");
}
final void finalFunctionC(){
System.out.println("finalFunctionC");
}
void functionD(){}
}
class overrideFinalFunction extends finalFunction{
//@Override 添加@Override注解可以識(shí)別是否是override
public void finalFunctionA(){
System.out.println("override finalFunctionA");
}
public final void finalFunctionB(){
System.out.println("override finalFunctionB");
}
//final void finalFunctionC(){} //Cannot override the final method from finalFunction
@Override
void functionD(){} //真正的override方法
}
public class javaFinalFunction extends finalFunction{
public static void main(String args[]){
finalFunction ff = new finalFunction();
//ff.finalFunctionA(); //無法調(diào)用private方法
//ff.finalFunctionB();
overrideFinalFunction off = new overrideFinalFunction();
off.finalFunctionA(); //public方法
off.finalFunctionB();
}
}
【final類】
使用final類一般是出于設(shè)計(jì)原因,不允許該類被繼承。這樣可以保證類的行為不會(huì)改變,或許還能避免一些安全危機(jī)。Final類中所有的方法都隱式指定為final方法,因此無法被覆蓋(因?yàn)閒inal類禁止繼承,也就無法覆蓋其類中的方法)。在Java核心API中,有許多應(yīng)用final的例子,例如java.lang.String。為String類指定final防止覆蓋length()等方法。
對(duì)于final域來說,即使將一個(gè)類聲明為final,類中的域不會(huì)自動(dòng)成為final域。
final class finalClass{
int testA = 2011;
}
//class extendFinalClassextends finalClass{} //can not extendthe final class finalClass
public class javaFinalClass{
public static void main(String args[]){
finalClass fc = new finalClass();
System.out.println(fc.testA);
fc.testA = 2012;
System.out.println(fc.testA);
}
}
相關(guān)文章
Javabean轉(zhuǎn)換成json字符并首字母大寫代碼實(shí)例
這篇文章主要介紹了javabean轉(zhuǎn)成json字符并首字母大寫代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02java實(shí)現(xiàn)sftp客戶端上傳文件以及文件夾的功能代碼
本篇文章主要介紹了java實(shí)現(xiàn)sftp客戶端上傳文件以及文件夾的功能代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-02-02Java使用list集合remove需要注意的事項(xiàng)(使用示例)
List集合的一個(gè)特點(diǎn)是它其中的元素是有序的,也就是說元素的下標(biāo)是根據(jù)插入的順序來的,在刪除頭部或者中間的一個(gè)元素后,后面的元素下標(biāo)會(huì)往前移動(dòng),本文給大家介紹Java使用list集合remove需要注意的事項(xiàng),感興趣的朋友一起看看吧2022-01-01java 動(dòng)態(tài)加載的實(shí)現(xiàn)代碼
這篇文章主要介紹了java 動(dòng)態(tài)加載的實(shí)現(xiàn)代碼的相關(guān)資料,Java動(dòng)態(tài)加載類主要是為了不改變主程序代碼,通過修改配置文件就可以操作不同的對(duì)象執(zhí)行不同的功能,需要的朋友可以參考下2017-07-07java實(shí)現(xiàn)后臺(tái)圖片跨域上傳功能
這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)后臺(tái)圖片跨域上傳功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Java?Date(日期)對(duì)象進(jìn)行格式化的思路詳解
Date類是經(jīng)常會(huì)使用到的一個(gè)用來處理日期、時(shí)間的一個(gè)類。Date類是在java.util包下的Date類,這篇文章主要介紹了Java?Date(日期)對(duì)象如何進(jìn)行格式化呢,需要的朋友可以參考下2022-09-09