Java中final關(guān)鍵字的使用與注意總結(jié)
前言
在java中可以將實(shí)例域定義為final。在構(gòu)建對(duì)象是必須初始化這樣的值。必須確保在每個(gè)構(gòu)造器執(zhí)行之后,這個(gè)域的值被設(shè)置,并且在后面的操作中不再對(duì)其修改。使用final聲明變量之后,這個(gè)值就不能修改,一般final類(lèi)型的變量都被聲明為靜態(tài)變量,而且是公有類(lèi)型的,它在內(nèi)存中被放在一個(gè)特有的公共區(qū)域。
也就是說(shuō),在Java語(yǔ)法中規(guī)定,final修飾的成員變量必須有程序員顯式地指定初始值。
定義格式為: public static final double pi = 3.1415926;
final修飾符大多應(yīng)用于基本類(lèi)型域,或不可變類(lèi)的域(如果類(lèi)中的每個(gè)方法都不會(huì)改變其對(duì)象,這種類(lèi)成為不可變類(lèi)。比如說(shuō)Java中的String類(lèi)就是一個(gè)不可變類(lèi)。)
如果定義了兩個(gè)相同的變量,都是final類(lèi)型的,這兩個(gè)相同的變量名有著不同的值,其實(shí)在內(nèi)存中是開(kāi)辟了兩個(gè)內(nèi)存空間,之前定義的變量的值會(huì)被后來(lái)定義的變量的值覆蓋掉。原理是變量名指向后來(lái)定義的變量值的內(nèi)存空間,之前定義的變量值會(huì)被Java虛擬機(jī)根據(jù)某種特定的算法在特定的時(shí)間處理掉。
在下面的代碼中詳細(xì)的介紹了final類(lèi)型的變量如何進(jìn)行定義和初始化:
public class FinalVariableText {
//定義成員變量是指定默認(rèn)值,合法
final int a = 6;
//下面變量將在構(gòu)造器或初始化塊中分配初始值
final String str;
final int c ;
final static double d;
//既沒(méi)有指定默認(rèn)值,也沒(méi)有在初始化塊、構(gòu)造器中指定初始值
//下面定義的ch實(shí)例變量是不合法的
//final char ch;
{
//在初始化塊中只懂初始值,合法
str ="hello" ;
//定義a實(shí)例變量已經(jīng)有初始值了,不能為a重新賦值。下面的語(yǔ)句是不正確的
//a = 9;
}
//靜態(tài)初始化塊
static {
// d是靜態(tài)成員變量,必須在靜態(tài)初始化塊中為其指定初始值
d = 5.6;
}
//構(gòu)造器,可對(duì) 沒(méi)有設(shè)置初始值的成員變量設(shè)置初始值
//構(gòu)造器必須與類(lèi)名相同,這一點(diǎn)注意!
public FinalVariableText(){
//如果在初始化塊中對(duì)str賦初值,在構(gòu)造器中在為str重新賦值,是不合法的,程序會(huì)拋出錯(cuò)誤。
c = 5;
}
public void changeFinal() {
//普通方法不能為final修飾的成員變量賦值
//d = 1.3;
//也不能在普通方法中為沒(méi)有設(shè)置初始值的final類(lèi)型的變量賦初值
//ch = 'ch';
}
public static void main(String[] args) {
FinalVariableText ff = new FinalVariableText();
System.out.println(ff.a);
System.out.println(ff.c);
System.out.println(ff.str);
System.out.println(ff.d);
}
結(jié)果:
6
5
hello
5.6
注意:
如果打算在構(gòu)造器、初始化塊中對(duì)final類(lèi)型的成員變量進(jìn)行初始化,則不要在初始化之前訪問(wèn)成員變量的值,否則會(huì)引發(fā)程序報(bào)錯(cuò)。
final也存在局部變量的情況
系統(tǒng)不會(huì)對(duì)局部變量進(jìn)行初始化,局部變量必須由程序員顯式的進(jìn)行初始化,因此使用final修飾局部變量的時(shí)候,既可以在定義是設(shè)定默認(rèn)值,也可以不指定默認(rèn)值。如果在定義是沒(méi)有進(jìn)行設(shè)定默認(rèn)值,則可以在后面的代碼中對(duì)該final變量賦初值,但只能一次,不可以重復(fù)賦值。當(dāng)然如果在定義變量的時(shí)候就已經(jīng)指定默認(rèn)值,在后面的代碼中就沒(méi)有必要也不允許對(duì)該變量在進(jìn)行賦值操作。
public void text(final int a) {
//不能對(duì)fianl修飾的形參進(jìn)行賦值操作
//a = 5; 該語(yǔ)句是不合法的
}
public static void main(String[] args) {
//定義final局部變量時(shí),指定初始值,則該變量再無(wú)法進(jìn)行賦值了
final String str = "str";
//下面的語(yǔ)句會(huì)報(bào)錯(cuò),不合法
//str = "Java";
//定義final變量沒(méi)有指定默認(rèn)值,則可以被賦值一次
final int d;
d = 5;
//再對(duì)d進(jìn)行新的賦值,不合法
// d = 8;
}
Final修飾基本類(lèi)型變量和引用類(lèi)型的變量的區(qū)別
Final修飾基本類(lèi)型變量上面已經(jīng)講述的很清楚了,那引用類(lèi)型的變量會(huì)有什么不同呢?對(duì)于引用類(lèi)型的變量而言,它僅僅是保存了一個(gè)引用關(guān)系,final只保證這個(gè)引用類(lèi)型變量所引用的地址不會(huì)改變,即一直引用同一個(gè)對(duì)象,但這個(gè)對(duì)象完全可以發(fā)生改變。下面通過(guò)代碼來(lái)驗(yàn)證一下:
class Person1{
private int age;
//有一個(gè)參數(shù)的構(gòu)造函數(shù)
public Person1(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class FinalReferenceText {
public static void main(String[] args) {
final int [] arr = {5,6,12,9};
System.out.println(Arrays.toString(arr));
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
arr[2] = -8;
System.out.println(Arrays.toString(arr));
//下面對(duì)arr重新賦值,非法
//arr = null;
//final 修飾Person變量,p是一個(gè)引用變量
final Person1 p = new Person1(45);
//改變Person對(duì)象的實(shí)例變量,合法
p.setAge(55);
System.out.println(p.getAge());
//下面對(duì)p重新賦值,非法
//p = null;
}
}
結(jié)果:
[5, 6, 12, 9]
[5, 6, 9, 12]
[5, 6, -8, 12]
55
final方法
Final修飾的方法不可被重寫(xiě),如果處于某種原因,不希望子類(lèi)重寫(xiě)父類(lèi)的某個(gè)方法,則可以使用final關(guān)鍵字修飾該方法。
如果父類(lèi)中的方法的是公有的,則子類(lèi)中不能有一個(gè)一樣方法名,一樣參數(shù)的方法,但如果父類(lèi)中的方法是私有的,那么子類(lèi)中完全可以寫(xiě)一個(gè)一樣的方法。
對(duì)于private類(lèi)型的方法,由于其只能在當(dāng)前類(lèi)中可見(jiàn),其子類(lèi)無(wú)法訪問(wèn)到該方法,所以子類(lèi)無(wú)法重寫(xiě)該方法,那么,如果子類(lèi)中存在一個(gè)與父類(lèi)private方法有相同方法名,一樣的參數(shù)列表,相同的返回值的方法,也不是方法的重寫(xiě),只是重新定義了一個(gè)新的方法。因此,final修飾一個(gè)private方法,依然可以在其子類(lèi)中定義和父類(lèi)private類(lèi)型一樣的方法,不會(huì)有程序錯(cuò)誤。
public class PrivateFinalText{
//如果將訪問(wèn)修飾符改成public,則其子類(lèi)中的方法定義在程序編譯時(shí)會(huì)報(bào)錯(cuò)
private final void text();
}
class Sub extends PrivateFinalText{
//下面的方法完全沒(méi)有問(wèn)題
public void text();
}
以上是我目前對(duì)Java中final關(guān)鍵字的總結(jié),稍后會(huì)有補(bǔ)充?。。?/p>
總結(jié)
到此這篇關(guān)于Java中final關(guān)鍵字的文章就介紹到這了,更多相關(guān)Java的final關(guān)鍵字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java使用任務(wù)架構(gòu)執(zhí)行任務(wù)調(diào)度示例
在Java 5.0之前啟動(dòng)一個(gè)任務(wù)是通過(guò)調(diào)用Thread類(lèi)的start()方法來(lái)實(shí)現(xiàn)的,5.0里提供了一個(gè)新的任務(wù)執(zhí)行架構(gòu)使你可以輕松地調(diào)度和控制任務(wù)的執(zhí)行,并且可以建立一個(gè)類(lèi)似數(shù)據(jù)庫(kù)連接池的線程池來(lái)執(zhí)行任務(wù),下面看一個(gè)示例2014-01-01
自定義注解實(shí)現(xiàn)Spring容器注入Bean方式(類(lèi)似于mybatis的@MapperScans)
本文介紹了如何通過(guò)自定義注解@MyService和@MyServiceScans在SpringBoot項(xiàng)目中自動(dòng)將指定包下的類(lèi)注入Spring容器,詳細(xì)解釋了創(chuàng)建自定義注解、定義包掃描器ClassPathBeanDefinitionScanner的作用與實(shí)現(xiàn)2024-09-09
Spring Web MVC和Hibernate的集成配置詳解
這篇文章主要介紹了Spring Web MVC和Hibernate的集成配置詳解,具有一定借鑒價(jià)值,需要的朋友可以參考下2017-12-12
IDEA運(yùn)行SSM項(xiàng)目的超詳細(xì)圖解教程
SSM項(xiàng)目部署其實(shí)很簡(jiǎn)單,下面這篇文章主要給大家介紹了關(guān)于IDEA運(yùn)行SSM項(xiàng)目的超詳細(xì)圖解教程,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10

