一、關(guān)鍵字final的理解
1、final數(shù)據(jù)
在java編程語言中,有時(shí)候需要告知編譯器一段數(shù)據(jù)是不變的編譯期常量。對(duì)于這種情況,編譯器可以將此常量值帶入需要用到它的計(jì)算式子當(dāng)中,這種在編譯時(shí)執(zhí)行計(jì)算式的方法減輕了運(yùn)行時(shí)的開銷。通常,這類常量數(shù)據(jù)都是基本類型的數(shù)據(jù),并賦予關(guān)鍵字final,同時(shí)在對(duì)此常量定義時(shí)需要進(jìn)行賦值。
值得注意的是:對(duì)于基本類型,使用final關(guān)鍵字將使數(shù)值恒定不變;而對(duì)于對(duì)象引用,final則是使引用恒定不變。一旦引用被初始化為指向一個(gè)對(duì)象時(shí),它也就無法再指向另外一個(gè)對(duì)象,然而該對(duì)象本身是可以被修改的。通常,對(duì)于一個(gè)既是static又是final的域只占一段不能改變的存儲(chǔ)空間。
下面的例子驗(yàn)證了final數(shù)據(jù)的含義。
class Hank
{
int i;
public Hank(int i){this.i=i;}
}
public class FinalTest
{
private String s;
public FinalTest(String s){this.s=s;}
private final int value=20;
private static final int INT_1=50;
public static final int INT_2=60;
static final int INT_3=70;
private final Hank h1=new Hank(1);
private static final Hank h2=new Hank(2);
private Hank h3=new Hank(3);
private final int[] a={1,2,3,4,5};
public String toString()
{
return s+“: ”+“INT_2= ”+INT_2;
}
public static void main(String[] args)
{
FinalTest ft1=new FinalTest(“ft1”);
//ft1.value++;常量值不能被修改
ft1.h1.i++;//對(duì)象引用不能改變,但是其對(duì)象本身是可以修改的
ft1.h3=new Hank(2);
//ft1.h1=new Hank(1);常量對(duì)象引用不能再指向另一個(gè)對(duì)象引用
for(int i=0;i《ft1.a.length;i++)
{
ft1.a[i]++; //對(duì)象引用不能改變,但是其對(duì)象本身是可以修改的
System.out.println(ft1.a[i]);
}
//ft1.a=new int[3]; 常量對(duì)象引用不能再指向另一個(gè)對(duì)象引用
}
}
2、空白final
被聲明為final但又沒有給定初值的域即為空白final,編譯器確保使用前必須初始化空白final。比如:
class Blank
{
private int i;
Blank(int i){this.i=i;System.out.println(“Blank.i=”+this.i);}
}
public class BlankFinal
{
private final int i;//blank final
private final Blank b;//blank final reference
BlankFinal()
{
i=1;b=new Blank(1);//使用前必須初始化
System.out.println(“BlankFinal.i=”+this.i);
}
BlankFinal(int i)
{
this.i=i;b=new Blank(i); //使用前必須初始化
System.out.println(“BlankFinal.i=”+this.i);
}
public static void main(String[] args)
{
new BlankFinal();//Blank.i=1;BlankFinal.i=1;
new BlankFinal(2); //Blank.i=2;BlankFinal.i=2;
}
}
3、final參數(shù)
Java允許在函數(shù)參數(shù)列表中以聲明的方式將參數(shù)指明為final,這使得在函數(shù)體當(dāng)中修改參數(shù)引用所指向的對(duì)象變得不合法。比如說:
class Args
{
public void f(String s){System.out.println(s);}
}
public class ArgsFinal
{
void has(final Args arg)
{
//arg=new Args();不能修改final參數(shù)
arg.f(“with final”);
}
void dnthas(Args arg)
{
arg=new Args();//能修改final參數(shù)
arg.f(“without final”);
}
public static void main(String[] args)
{
ArgsFinal af=new ArgsFinal();
Args ar=new Args();
af.has(ar);//with final
af.dnthas(ar);//without final
}
}
4、final類
如果不想繼承某個(gè)類,則可以考慮將此類設(shè)置成final的形式。即是說,程序員對(duì)該類不能做任何改動(dòng),同時(shí)也意味著它不會(huì)有子類。比如:
Class Base{ …}
Final Class SubClass{…}
//! Class Derived extends SubClass{…}不能由final類SubClass導(dǎo)出新類
需要注意的是,所有final類中的方法都隱式的final,他們是無法被覆蓋或修改的,因此在其中的方法顯示指明為final就顯得有些多此一舉了。
二、Java中的final關(guān)鍵字所起的作用
1、final修飾類中的屬性或者變量
無論屬性是基本類型還是引用類型,final所起的作用都是變量里面存放的“值”不能變。
這個(gè)值,對(duì)于基本類型來說,變量里面放的就是實(shí)實(shí)在在的值,如1,“abc”等。
而引用類型變量里面放的是個(gè)地址,所以用final修飾引用類型變量指的是它里面的地址不能變,并不是說這個(gè)地址所指向的對(duì)象或數(shù)組的內(nèi)容不可以變,這個(gè)一定要注意。
例如:類中有一個(gè)屬性是final Person p=new Person(“name”); 那么你不能對(duì)p進(jìn)行重新賦值,但是可以改變p里面屬性的值,p.setName(‘newName’);
final修飾屬性,聲明變量時(shí)可以不賦值,而且一旦賦值就不能被修改了。對(duì)final屬性可以在三個(gè)地方賦值:聲明時(shí)、初始化塊中、構(gòu)造方法中。總之一定要賦值。
2、final修飾類中的方法
作用:可以被繼承,但繼承后不能被重寫。
3、final修飾類
作用:類不可以被繼承。
思考一個(gè)有趣的現(xiàn)象:
byte b1=1;
byte b2=3;
byte b3=b1+b2;//當(dāng)程序執(zhí)行到這一行的時(shí)候會(huì)出錯(cuò),因?yàn)閎1、b2可以自動(dòng)轉(zhuǎn)換成int類型的變量,運(yùn)算時(shí)java虛擬機(jī)對(duì)它進(jìn)行了轉(zhuǎn)換,結(jié)果導(dǎo)致把一個(gè)int賦值給byte-----出錯(cuò)
如果對(duì)b1 b2加上final就不會(huì)出錯(cuò)
final byte b1=1;
final byte b2=3;
byte b3=b1+b2;//不會(huì)出錯(cuò),相信你看了上面的解釋就知道原因了。
評(píng)論
查看更多