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

深入解析Java編程中final關(guān)鍵字的使用

 更新時間:2016年01月03日 16:14:04   作者:zhangjunhd  
這篇文章主要介紹了Java編程中final關(guān)鍵字的使用,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下

在Java中聲明屬性、方法和類時,可使用關(guān)鍵字final來修飾。final變量即為常量,只能賦值一次;final方法不能被子類重寫;final類不能被繼承。
1.final成員
聲明 final 字段有助于優(yōu)化器作出更好的優(yōu)化決定,因為如果編譯器知道字段的值不會更改,那么它能安全地在寄存器中高速緩存該值。final 字段還通過讓編譯器強制該字段為只讀來提供額外的安全級別。
 
1.1關(guān)于final成員賦值
1)在java中,普通變量可默認初始化。但是final類型的變量必須顯式地初始化。
 
2)final 成員能且只能被初始化一次。
 
3)final成員必須在聲明時(在final變量定義時直接給其賦值)或者在構(gòu)造函數(shù)中被初始化,而不能在其它的地方被初始化。
示例1 Bat.java

public class Bat {
  final double PI = 3.14; // 在定義時賦值
  final int i; // 因為要在構(gòu)造函數(shù)中進行初始化,所以此處便不可再賦值
  final List<Bat> list; // 因為要在構(gòu)造函數(shù)中進行初始化,所以此處便不可再賦值
 
  Bat() {
    i = 100;
    list = new LinkedList<Bat>();
  }
 
  Bat(int ii, List<Bat> l) {
    i = ii;
    list = l;
  }
 
  public static void main(String[] args) {
    Bat b = new Bat();
    b.list.add(new Bat());
    // b.i=25;
    // b.list=new ArrayList<Bat>();
    System.out.println("I=" + b.i + " List Type:" + b.list.getClass());
    b = new Bat(23, new ArrayList<Bat>());
    b.list.add(new Bat());
    System.out.println("I=" + b.i + " List Type:" + b.list.getClass());
  }
}

 
結(jié)果:

I=100 List Type:class java.util.LinkedList
I=23 List Type:class java.util.ArrayList

 
在main方法中有兩行語句注釋掉了,如果你去掉注釋,程序便無法通過編譯,這便是說,不論是i的值或是list的類型,一旦初始化,確實無法再更改。然而b可以通過重新初始化來指定i的值或list的類型。
 
1.2 final引用字段的無效初始化
要正確使用final字段有點麻煩,對于其構(gòu)造子能拋出異常的對象引用來說尤其如此。因為 final 字段在每個構(gòu)造器中必須只初始化一次,如果 final 對象引用的構(gòu)造器可能拋出異常,編譯器可能會報錯,說該字段沒有被初始化。編譯器一般比較智能化,足以發(fā)現(xiàn)在兩個互斥代碼分支(比如,if...else 塊)的每個分支中的初始化恰好只進行了一次,但是它對 try...catch 塊通常不會如此“寬容”。
下面這段代碼通常會出現(xiàn)問題。

class Thingie {
  public static Thingie getDefaultThingie() {
    return new Thingie();
  }
}
 
public class Foo {
  private final Thingie thingie;
 
  public Foo() {
    try {
      thingie = new Thingie();
    } catch (Exception e) {
      thingie = Thingie.getDefaultThingie();//Error:The final field thingie may already have been assigned
    }
  }
}

 
你可以這樣修改。

public class Foo {
  private final Thingie thingie;
 
  public Foo() {
    Thingie tempThingie;
    try {
      tempThingie = new Thingie();
    } catch (Exception e) {
      tempThingie = Thingie.getDefaultThingie();
    }
    thingie = tempThingie;
  }
}

 
1.3關(guān)于final成員使用
當(dāng)你在類中定義變量時,在其前面加上final關(guān)鍵字,那便是說,這個變量一旦被初始化便不可改變,這里不可改變的意思對基本類型來說是其值不可變,而對于對象變量來說其引用不可再變。然而,對象其本身卻是可以被修改的,Java并未提供使任何對象恒定不變的途徑。這一限制同樣適合數(shù)組,它也是對象。
示例2

private final int VAL_ONE=9;
private static final int VAL_TWO=99;
public static final int VAL_THREE=999;

由于VAL_ONE 和VAL_TOW 是帶有編譯期數(shù)值的final 原始類型,所以它們二者均可以用作編譯期常量,并且沒有重大區(qū)別。VAL_THREE是一種更加典型的對常量進行定義的方式:定義為 public,則可以被用于包之外;定義為 static 來強調(diào)只有一份;定義為 final 來說明它是一個常量。
final標(biāo)記的變量即成為常量,但這個“常量”也只能在這個類的內(nèi)部使用,不能在類的外部直接使用。但是當(dāng)我們用public static final 共同標(biāo)記常量時,這個常量就成為全局的常量(一個既是static又是final的字段只占據(jù)一段不能改變的存儲空間)。而且這樣定義的常量只能在定義時賦值,其他地方都不行。
示例3

class Value {
  int i;
 
  public Value(int i) {
    this.i = i;
  }
}
 
public class FinalData {
  private static Random rand = new Random();
 
  private String id;
 
  public FinalData(String id) {
    this.id = id;
  }
 
  private final int i4 = rand.nextInt(20);
 
  static final int i5 = rand.nextInt(20);
 
  public String toString() {
    return id + ":" + "i4:" + i4 + ", i5=" + i5;
  }
 
  public static void main(String[] args) {
    FinalData fd1 = new FinalData("fd1");
    System.out.println(fd1);
    System.out.println("Creating new FinalData");
    FinalData fd2 = new FinalData("fd2");
    System.out.println(fd1);
    System.out.println(fd2);
  }
}

 
結(jié)果

fd1:i4:6, i5=3
Creating new FinalData
fd1:i4:6, i5=3
fd2:i4:17, i5=3

示例部分展示了將final 數(shù)值定義為static(i5) 和非static(i4) 的區(qū)別。此區(qū)別只有在數(shù)值在運行期內(nèi)被初始化時才會顯現(xiàn),這是因為編譯器對編譯期數(shù)值一視同仁。(并且它們可能因優(yōu)化而消失。)當(dāng)你運行程序時,就會看到這個區(qū)別。請注意,在fd1 和fd2 中, i5 的值是不可以通過創(chuàng)建第二個FinalData 對象而加以改變的。這是因為它是 static,在裝載時已被初始化,而不是每次創(chuàng)建新對象時都初始化。
示例4

class Value {
  int i;
 
  public Value(int i) {
    this.i = i;
  }
}
 
public class … {
  private Value v1=new Value(11);
  private final Value v2=new Value(22);
  private static final Value v3=new Value(33);
  …
}
 
public static void main(String[] args) {
  …
  fd1.v2.i++;// OK--Object isn't constant!
  fd1.v1=new Value(9);//OK--not final
  fd1.v2=new Value(0);//Error:Can't change reference
  fd1.v3=new Value(1);//Error:Can't change reference
  …
}

從v1 到v3 的變量說明了final 引用的意義。正如你在main( )中所看到的,不能因為v2 是final 的,就認為你無法改變它的值。由于它是一個引用,final 意味著你無法將v2 再次指向另一個新的對象。
示例5

public class … {
  private final int[] a={1,2,3,4,5,6};
  …
}
 
public static void main(String[] args) {
  …
  for(int i=0;i<fd1.a.length;i++)
 fd1.a[i]++;// OK--Object isn't constant!
  fd1.a=new int[3];//Error:Can't change reference  …
}

對數(shù)組具有同樣的意義(可以改變它的值,但不能指向一個新的對象),數(shù)組是另一種引用。
 
1.4解決final數(shù)組的局限性
盡管數(shù)組引用能被聲明成 final,但是該數(shù)組的元素卻不能。這意味著暴露 public final 數(shù)組字段的或者通過它們的方法將引用返回給這些字段的類都不是不可改變的。

// Not immutable -- the states array could be modified by a malicious
// callerpublic
class DangerousStates {
  private final String[] states = new String[] { "Alabama", "Alaska", "ect" };
 
  public String[] getStates() {
    return states;
  }
}

 
同樣,盡管對象引用可以被聲明成 final 字段,而它所引用的對象仍可能是可變的。如果想要使用 final 字段創(chuàng)建不變的對象,必須防止對數(shù)組或可變對象的引用“逃離”你的類。要不用重復(fù)克隆該數(shù)組做到這一點,一個簡單的方法是將數(shù)組轉(zhuǎn)變成 List。

// Immutable -- returns an unmodifiable List insteadpublic
class SafeStates {
  private final String[] states = new String[] { "Alabama", "Alaska", "ect" };
 
  private final List statesAsList = new AbstractList() {
    public Object get(int n) {
      return states[n];
    }
 
    public int size() {
      return states.length;
    }
  };
 
  public List getStates() {
    return statesAsList;
  }
}

 
1.5關(guān)于final參數(shù)使用
還有一種用法是定義方法中的參數(shù)為final,對于基本類型的變量,這樣做并沒有什么實際意義,因為基本類型的變量在調(diào)用方法時是傳值的,也就是說你可以在方法中更改這個參數(shù)變量而不會影響到調(diào)用語句,然而對于對象變量,卻顯得很實用,因為對象變量在傳遞時是傳遞其引用,這樣你在方法中對對象變量的修改也會影響到調(diào)用語句中的對象變量,當(dāng)你在方法中不需要改變作為參數(shù)的對象變量時,明確使用final進行聲明,會防止你無意的修改而影響到調(diào)用方法。
 
1.6關(guān)于內(nèi)部類中的參數(shù)變量
另外方法中的內(nèi)部類在用到方法中的參變量時,此參數(shù)變量必須聲明為final才可使用。
示例6 INClass.java

public class INClass {
  void innerClass(final String str) {
    class IClass {
      IClass() {
       System.out.println(str);
      }
    }
    IClass ic = new IClass();
  }
 
  public static void main(String[] args) {
    INClass inc = new INClass();
    inc.innerClass("Hello");
  }
}

2.final方法
2.1final方法用途
1)為了確保某個函數(shù)的行為在繼承過程中保持不變,并且不能被覆蓋(overridding),可以使用final方法。
 
2)class中所有的private和static方法自然就是final。
 
2.2 final與private關(guān)鍵字
類中所有的private方法都隱式地指定是final的。由于無法取用private方法,所以也就無法覆蓋它。
“覆蓋”只有在某方法是基類的接口的一部分時才會出現(xiàn)。即,必須能將一個對象向上轉(zhuǎn)型為它的基本類型并調(diào)用相同的方法。如果某方法為private,它就不是基類的接口的一部分。它僅是一些隱藏于類中的代碼,只不過是具有相同的名稱而已。但如果在導(dǎo)出類以相同的方法生成一個public、protected或包訪問權(quán)限方法的話,該方法就不會產(chǎn)生在基類中出現(xiàn)的“僅具有相同名稱”的情況。此時,你并沒有覆蓋該方法,僅是生成了一個新的方法。由于private方法無法觸及而且能有效隱藏,所以除了把它看成是因為它所歸屬的類的組織結(jié)構(gòu)的原因而存在外,其他任何事物都不需要考慮它。
3.final類
將某個類的整體定義為final 時,該類無法被繼承。而且由于final類禁止繼承,所以final類中所有的方法都隱式指定為final的,因為無法覆蓋它們。
final 用于類或方法是為了防止方法間的鏈接被破壞。例如,假定類 X 的某個方法的實現(xiàn)假設(shè)了方法 M 將以某種方式工作。將 X 或 M 聲明成 final 將防止派生類以這種方式重新定義 M,從而導(dǎo)致 X 的工作不正常。盡管不用這些內(nèi)部相關(guān)性來實現(xiàn) X 可能會更好,但這不總是可行的,而且使用 final 可以防止今后這類不兼容的更改。

PS:final,finally和finallize的區(qū)別

  1. final用于申明屬性,方法和類,表示屬性不可變,方法不可以被覆蓋,類不可以被繼承。
  2. finally是異常處理語句結(jié)構(gòu)中,表示總是執(zhí)行的部分?! ?/li>
  3. finallize表示是object類一個方法,在垃圾回收機制中執(zhí)行的時候會被調(diào)用被回收對象的方法。

相關(guān)文章

  • Intellij Idea修改代碼方法參數(shù)自動提示快捷鍵的操作

    Intellij Idea修改代碼方法參數(shù)自動提示快捷鍵的操作

    這篇文章主要介紹了Intellij Idea修改代碼方法參數(shù)自動提示快捷鍵的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • Java使用新浪微博API通過賬號密碼方式登陸微博的實例

    Java使用新浪微博API通過賬號密碼方式登陸微博的實例

    這篇文章主要介紹了Java使用新浪微博API通過賬號密碼方式登陸微博的實例,一般來說第三方App都是采用OAuth授權(quán)認證然后跳轉(zhuǎn)之類的方法,而本文所介紹的賬號方式則更具有自由度,需要的朋友可以參考下
    2016-02-02
  • reactor-logback的AsyncAppender執(zhí)行流程源碼解讀

    reactor-logback的AsyncAppender執(zhí)行流程源碼解讀

    這篇文章主要為大家介紹了reactor-logback的AsyncAppender執(zhí)行流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • SpringBoot?自定義注解實現(xiàn)涉密字段脫敏

    SpringBoot?自定義注解實現(xiàn)涉密字段脫敏

    關(guān)于數(shù)據(jù)脫敏,網(wǎng)上的文章都是硬編碼規(guī)則,比如對身份證,手機號,郵件地址等固定寫法脫敏。本文在此基礎(chǔ)上,拓展動態(tài)從數(shù)據(jù)庫查出涉密關(guān)鍵字執(zhí)行脫敏操作。感興趣的同學(xué)可以參考閱讀
    2023-03-03
  • Feign Client 超時時間配置不生效的解決

    Feign Client 超時時間配置不生效的解決

    這篇文章主要介紹了Feign Client 超時時間配置不生效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring Boot 基于注解的 Redis 緩存使用詳解

    Spring Boot 基于注解的 Redis 緩存使用詳解

    本篇文章主要介紹了Spring Boot 基于注解的 Redis 緩存使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • nacos-discovery包名層級問題解決

    nacos-discovery包名層級問題解決

    這篇文章主要為大家介紹了nacos-discovery包名層級問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • Mybatis-plus操作json字段實戰(zhàn)教程

    Mybatis-plus操作json字段實戰(zhàn)教程

    這篇文章主要介紹了Mybatis-plus操作json字段實戰(zhàn)教程,本文結(jié)合實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-02-02
  • 詳解Java的Spring框架中bean的定義以及生命周期

    詳解Java的Spring框架中bean的定義以及生命周期

    這篇文章主要介紹了Java的Spring框架中bean的定義以及生命周期,bean的實例化是Java web開發(fā)中的重要基礎(chǔ),需要的朋友可以參考下
    2015-12-12
  • Java實現(xiàn)斷點下載服務(wù)端與客戶端的示例代碼

    Java實現(xiàn)斷點下載服務(wù)端與客戶端的示例代碼

    這篇文章主要為大家介紹了如何實現(xiàn)服務(wù)端(Spring Boot)與客戶端(Android)的斷點下載與下載續(xù)傳功能,文中的示例代碼講解詳細,需要的可以參考一下
    2022-08-08

最新評論