欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入淺析Java中的final關(guān)鍵字

 更新時(shí)間:2015年12月14日 10:23:05   作者:海 子  
在Java中,final關(guān)鍵字可以用來(lái)修飾類、方法和變量(包括成員變量和局部變量),下面通過本篇文章給大家介紹java中的final關(guān)鍵字,對(duì)java fina關(guān)鍵字相關(guān)知識(shí)感興趣的朋友一起看看吧

談到final關(guān)鍵字,想必很多人都不陌生,在使用匿名內(nèi)部類的時(shí)候可能會(huì)經(jīng)常用到final關(guān)鍵字。另外,Java中的String類就是一個(gè)final類,那么今天我們就來(lái)了解final這個(gè)關(guān)鍵字的用法。下面是本文的目錄大綱:

  一.final關(guān)鍵字的基本用法

  二.深入理解final關(guān)鍵字

  若有不正之處,請(qǐng)多多諒解并歡迎指正。

final 對(duì)于常量來(lái)說(shuō),意味著值不能改變,例如 final int i=100。這個(gè)i的值永遠(yuǎn)都是100。但是對(duì)于變量來(lái)說(shuō)又不一樣,只是標(biāo)識(shí)這個(gè)引用不可被改變,例如 final File f=new File("c:\\test.txt");那么這個(gè)f一定是不能被改變的,如果f本身有方法修改其中的成員變量,例如是否可讀,是允許修改的。形象的比喻:一個(gè)女子定義了一個(gè)final的老公,這個(gè)老公的職業(yè)和收入都是允許改變的,只是這個(gè)女人不會(huì)換老公而已。

一.final關(guān)鍵字的基本用法

  在Java中,final關(guān)鍵字可以用來(lái)修飾類、方法和變量(包括成員變量和局部變量)。下面就從這三個(gè)方面來(lái)了解一下final關(guān)鍵字的基本用法。

  1.修飾類

   當(dāng)用final修飾一個(gè)類時(shí),表明這個(gè)類不能被繼承。也就是說(shuō),如果一個(gè)類你永遠(yuǎn)不會(huì)讓他被繼承,就可以用final進(jìn)行修飾。final類中的成員變量可以根據(jù)需要設(shè)為final,但是要注意final類中的所有成員方法都會(huì)被隱式地指定為final方法。

  在使用final修飾類的時(shí)候,要注意謹(jǐn)慎選擇,除非這個(gè)類真的在以后不會(huì)用來(lái)繼承或者出于安全的考慮,盡量不要將類設(shè)計(jì)為final類。

  2.修飾方法

  下面這段話摘自《Java編程思想》第四版第143頁(yè):

  “使用final方法的原因有兩個(gè)。第一個(gè)原因是把方法鎖定,以防任何繼承類修改它的含義;第二個(gè)原因是效率。在早期的Java實(shí)現(xiàn)版本中,會(huì)將final方法轉(zhuǎn)為內(nèi)嵌調(diào)用。但是如果方法過于龐大,可能看不到內(nèi)嵌調(diào)用帶來(lái)的任何性能提升。在最近的Java版本中,不需要使用final方法進(jìn)行這些優(yōu)化了?!?br />

  因此,如果只有在想明確禁止 該方法在子類中被覆蓋的情況下才將方法設(shè)置為final的。

  注:類的private方法會(huì)隱式地被指定為final方法。

  3.修飾變量

  修飾變量是final用得最多的地方,也是本文接下來(lái)要重點(diǎn)闡述的內(nèi)容。首先了解一下final變量的基本語(yǔ)法:

  對(duì)于一個(gè)final變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改;如果是引用類型的變量,則在對(duì)其初始化之后便不能再讓其指向另一個(gè)對(duì)象。

  舉個(gè)例子:

  上面的一段代碼中,對(duì)變量i和obj的重新賦值都報(bào)錯(cuò)了。

二.深入理解final關(guān)鍵字

  在了解了final關(guān)鍵字的基本用法之后,這一節(jié)我們來(lái)看一下final關(guān)鍵字容易混淆的地方。

1.類的final變量和普通變量有什么區(qū)別?

  當(dāng)用final作用于類的成員變量時(shí),成員變量(注意是類的成員變量,局部變量只需要保證在使用之前被初始化賦值即可)必須在定義時(shí)或者構(gòu)造器中進(jìn)行初始化賦值,而且final變量一旦被初始化賦值之后,就不能再被賦值了。

  那么final變量和普通變量到底有何區(qū)別呢?下面請(qǐng)看一個(gè)例子:

public class Test {
  public static void main(String[] args) {
    String a = "hello2"; 
    final String b = "hello";
    String d = "hello";
    String c = b + 2; 
    String e = d + 2;
    System.out.println((a == c));
    System.out.println((a == e));
  }
} 
true
false 

  大家可以先想一下這道題的輸出結(jié)果。為什么第一個(gè)比較結(jié)果為true,而第二個(gè)比較結(jié)果為fasle。這里面就是final變量和普通變量的區(qū)別了,當(dāng)final變量是基本數(shù)據(jù)類型以及String類型時(shí),如果在編譯期間能知道它的確切值,則編譯器會(huì)把它當(dāng)做編譯期常量使用。也就是說(shuō)在用到該final變量的地方,相當(dāng)于直接訪問的這個(gè)常量,不需要在運(yùn)行時(shí)確定。這種和C語(yǔ)言中的宏替換有點(diǎn)像。因此在上面的一段代碼中,由于變量b被final修飾,因此會(huì)被當(dāng)做編譯器常量,所以在使用到b的地方會(huì)直接將變量b 替換為它的  值。而對(duì)于變量d的訪問卻需要在運(yùn)行時(shí)通過鏈接來(lái)進(jìn)行。想必其中的區(qū)別大家應(yīng)該明白了,不過要注意,只有在編譯期間能確切知道final變量值的情況下,編譯器才會(huì)進(jìn)行這樣的優(yōu)化,比如下面的這段代碼就不會(huì)進(jìn)行優(yōu)化:

public class Test {
  public static void main(String[] args) {
    String a = "hello2"; 
    final String b = getHello();
    String c = b + 2; 
    System.out.println((a == c));
  }
  public static String getHello() {
    return "hello";
  }
} 

  這段代碼的輸出結(jié)果為false。

2.被final修飾的引用變量指向的對(duì)象內(nèi)容可變嗎?

  在上面提到被final修飾的引用變量一旦初始化賦值之后就不能再指向其他的對(duì)象,那么該引用變量指向的對(duì)象的內(nèi)容可變嗎?看下面這個(gè)例子:

public class Test {
  public static void main(String[] args) {
    final MyClass myClass = new MyClass();
    System.out.println(++myClass.i);
  }
}
class MyClass {
  public int i = 0;
} 

  這段代碼可以順利編譯通過并且有輸出結(jié)果,輸出結(jié)果為1。這說(shuō)明引用變量被final修飾之后,雖然不能再指向其他對(duì)象,但是它指向的對(duì)象的內(nèi)容是可變的。

3.final和static

  很多時(shí)候會(huì)容易把static和final關(guān)鍵字混淆,static作用于成員變量用來(lái)表示只保存一份副本,而final的作用是用來(lái)保證變量不可變??聪旅孢@個(gè)例子:

public class Test {
  public static void main(String[] args) {
    MyClass myClass1 = new MyClass();
    MyClass myClass2 = new MyClass();
    System.out.println(myClass1.i);
    System.out.println(myClass1.j);
    System.out.println(myClass2.i);
    System.out.println(myClass2.j);
  }
}
class MyClass {
  public final double i = Math.random();
  public static double j = Math.random();
} 

  運(yùn)行這段代碼就會(huì)發(fā)現(xiàn),每次打印的兩個(gè)j值都是一樣的,而i的值卻是不同的。從這里就可以知道final和static變量的區(qū)別了。

4.匿名內(nèi)部類中使用的外部局部變量為什么只能是final變量?

  這個(gè)問題請(qǐng)參見上一篇博文中《Java內(nèi)部類詳解》中的解釋,在此處不再贅述。

5.關(guān)于final參數(shù)的問題

  關(guān)于網(wǎng)上流傳的”當(dāng)你在方法中不需要改變作為參數(shù)的對(duì)象變量時(shí),明確使用final進(jìn)行聲明,會(huì)防止你無(wú)意的修改而影響到調(diào)用方法外的變量“這句話,我個(gè)人理解這樣說(shuō)是不恰當(dāng)?shù)摹?br />

  因?yàn)闊o(wú)論參數(shù)是基本數(shù)據(jù)類型的變量還是引用類型的變量,使用final聲明都不會(huì)達(dá)到上面所說(shuō)的效果。

  看這個(gè)例子就清楚了:

 

  上面這段代碼好像讓人覺得用final修飾之后,就不能在方法中更改變量i的值了。殊不知,方法changeValue和main方法中的變量i根本就不是一個(gè)變量,因?yàn)閖ava參數(shù)傳遞采用的是值傳遞,對(duì)于基本類型的變量,相當(dāng)于直接將變量進(jìn)行了拷貝。所以即使沒有final修飾的情況下,在方法內(nèi)部改變了變量i的值也不會(huì)影響方法外的i。

  再看下面這段代碼:

public class Test {
  public static void main(String[] args) {
    MyClass myClass = new MyClass();
    StringBuffer buffer = new StringBuffer("hello");
    myClass.changeValue(buffer);
    System.out.println(buffer.toString());
  }
}
class MyClass {
  void changeValue(final StringBuffer buffer) {
    buffer.append("world");
  }
} 

  運(yùn)行這段代碼就會(huì)發(fā)現(xiàn)輸出結(jié)果為 helloworld。很顯然,用final進(jìn)行修飾并沒有阻止在changeValue中改變buffer指向的對(duì)象的內(nèi)容。有人說(shuō)假如把final去掉了,萬(wàn)一在changeValue中讓buffer指向了其他對(duì)象怎么辦。有這種想法的朋友可以自己動(dòng)手寫代碼試一下這樣的結(jié)果是什么,如果把final去掉了,然后在changeValue中讓buffer指向了其他對(duì)象,也不會(huì)影響到main方法中的buffer,原因在于java采用的是值傳遞,對(duì)于引用變量,傳遞的是引用的值,也就是說(shuō)讓實(shí)參和形參同時(shí)指向了同一個(gè)對(duì)象,因此讓形參重新指向另一個(gè)對(duì)象對(duì)實(shí)參并沒有任何影響。

以上所述是小編給大家分享的Java中的final關(guān)鍵字詳解,希望大家喜歡。

相關(guān)文章

  • 利用Java工具類Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn)功能

    利用Java工具類Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn)功能

    這篇文章主要介紹了利用Java工具類Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn)功能,利用Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn),校驗(yàn)的Servlet與今天的第一篇是一樣的,唯一就是驗(yàn)證碼的生成是不一樣的,利用Hutool生成驗(yàn)證碼更快捷.需要的朋友可以參考下
    2022-10-10
  • 使用springboot開發(fā)的第一個(gè)web入門程序的實(shí)現(xiàn)

    使用springboot開發(fā)的第一個(gè)web入門程序的實(shí)現(xiàn)

    這篇文章主要介紹了使用springboot開發(fā)的第一個(gè)web入門程序的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • SpringBoot上傳臨時(shí)文件被刪除引起報(bào)錯(cuò)的解決

    SpringBoot上傳臨時(shí)文件被刪除引起報(bào)錯(cuò)的解決

    這篇文章主要介紹了SpringBoot上傳臨時(shí)文件被刪除引起報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java中數(shù)組的定義與使用

    Java中數(shù)組的定義與使用

    下面小編就為大家?guī)?lái)一篇java中數(shù)組的定義與使用小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2021-10-10
  • 基于Java手寫一個(gè)好用的FTP操作工具類

    基于Java手寫一個(gè)好用的FTP操作工具類

    網(wǎng)上百度了很多FTP的java?工具類,發(fā)現(xiàn)文章代碼都比較久遠(yuǎn),且代碼臃腫,即使搜到了代碼寫的還可以的,封裝的常用操作方法不全面。所以本文將手寫一個(gè)好用的Java?FTP操作工具類,需要的可以參考一下
    2022-04-04
  • java基礎(chǔ)之String知識(shí)總結(jié)

    java基礎(chǔ)之String知識(shí)總結(jié)

    今天帶大家來(lái)回顧一下Java基礎(chǔ),文中詳細(xì)總結(jié)了String的相關(guān)知識(shí),對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05
  • java中關(guān)于移位運(yùn)算符的demo與總結(jié)(推薦)

    java中關(guān)于移位運(yùn)算符的demo與總結(jié)(推薦)

    下面小編就為大家?guī)?lái)一篇java中關(guān)于移位運(yùn)算符的demo與總結(jié)(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2016-05-05
  • java中l(wèi)ist.forEach()和list.stream().forEach()區(qū)別

    java中l(wèi)ist.forEach()和list.stream().forEach()區(qū)別

    這篇文章主要介紹了java中l(wèi)ist.forEach()和list.stream().forEach()區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Spring Boot 如何整合連接池

    Spring Boot 如何整合連接池

    這篇文章主要介紹了Spring Boot 如何整合連接池,幫助大家更好的理解和學(xué)習(xí)spring boot框架,感興趣的朋友可以了解下
    2020-11-11
  • Mybatis詳解在注解sql時(shí)報(bào)錯(cuò)的解決方法

    Mybatis詳解在注解sql時(shí)報(bào)錯(cuò)的解決方法

    MyBatis-Plus 是一個(gè) Mybatis 增強(qiáng)版工具,在 MyBatis 上擴(kuò)充了其他功能沒有改變其基本功能,為了簡(jiǎn)化開發(fā)提交效率而存在,本篇文章帶你看看在注解sql時(shí)所報(bào)出的錯(cuò)誤解決
    2022-03-03

最新評(píng)論