程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> JAVA中的final症結字用法實例詳解

JAVA中的final症結字用法實例詳解

編輯:關於JAVA

JAVA中的final症結字用法實例詳解。本站提示廣大學習愛好者:(JAVA中的final症結字用法實例詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是JAVA中的final症結字用法實例詳解正文


本文實例講述了JAVA中的final症結字用法。分享給年夜家供年夜家參考,詳細以下:

依據高低文情況,java的症結字final也存在著纖細的差別,但平日指的是“這是沒法轉變的。”不想轉變的來由有兩種:一種是效力,另外一種是設計。因為兩個緣由相差很遠,所以症結子final能夠被誤用。

接上去引見一下應用到final的三中情形:數據,辦法,類

final數據

很多編程說話都有某種辦法,來向編譯器告訴一塊數據是恆定不變的。有時數據的恆定不變是很有效的,例如:

1. 一個編譯時恆定不變的常量
2. 一個在運轉時初始化,而你不願望它被轉變。

關於編譯期常量的這類情形,編譯器可以將該常量值代入任何能夠用到它的盤算式中,也就是說,可以在編譯期就履行盤算式,這加重了一些運轉時的累贅。在java中,這類常量必需是根本類型,而且以final表現。在對這個常量界說時,必需停止賦值。

一個等於static又是final的域只占一段不克不及轉變的存儲空間。

當final運用於對象援用時,而不是根本類型時,其寄義有些讓人困惑。對根本類型應用final不克不及轉變的是他的數值。而關於對象援用,不克不及轉變的是他的援用,而對象自己是可以修正的。一旦一個final援用被初始化指向一個對象,這個援用將不克不及在指向其他對象。java並未供給對任何對象恆定不變的支撐。這一限制也通用實用於數組,它也是對象。例如:

package finalPackage;
import java.util.*;
class Value {
  int i;
  public Value(int i) {
    this.i = i;
  }
}
/**
 * final數據常量
 * @author Administrator
 * 對根本類型應用final不克不及轉變的是它的數值。
 * 而關於對象援用,不克不及轉變的是他的援用,而對象自己是可以修正的。
 * 一旦一個final援用被初始化指向一個對象,這個援用將不克不及在指向其他對象。 
 * 留意,依據通例,等於static又是final的域(即編譯器常量)將用年夜寫表現,並用下劃朋分個單詞。
 */
public class FinalData {
  private static Random rand = new Random(47);
  private String id;
  public FinalData(String id) {
    this.id = id;
  }
  // 編譯經常量 Can be compile-time constants:
  private final int valueOne = 9;
  private static final int VALUE_TWO = 99;
  // 典范的公共常量 Typical public constant:
  public static final int VALUE_THREE = 39;
  // 運轉經常量 Cannot be compile-time constants:
  private final int i4 = rand.nextInt(20);
  static final int INT_5 = rand.nextInt(20);
  private Value v1 = new Value(11);
  private final Value v2 = new Value(22);
  private static final Value VAL_3 = new Value(33);
  // 數組 Arrays:
  private final int[] a = { 1, 2, 3, 4, 5, 6 };
  public String toString() {
    return id + ": " + "i4 = " + i4 + ", INT_5 = " + INT_5;
  }
  public static void main(String[] args) {
    FinalData fd1 = new FinalData("fd1");
    // ! fd1.valueOne++; // Error: can't change value
    fd1.v2.i++; // Object isn't constant!
    fd1.v1 = new Value(9); // OK -- not final
    for (int i = 0; i < fd1.a.length; i++)
      fd1.a[i]++; // Object isn't constant!
    // ! fd1.v2 = new Value(0); // Error: Can't
    // ! fd1.VAL_3 = new Value(1); // change reference
    // ! fd1.a = new int[3];
    System.out.println(fd1);
    System.out.println("Creating new FinalData");
    FinalData fd2 = new FinalData("fd2");
    System.out.println(fd1);
    System.out.println(fd2);
  }
  /**
   * 輸入成果:
   * fd1: i4 = 15, INT_5 = 18
   * Creating new FinalData
   * fd1: i4 = 15, INT_5 = 18
   * fd2: i4 = 13, INT_5 = 18
   */
}

因為valueOne和VALUE_TWO都是帶有編譯時數值的final根本類型,所以它們兩者都可以用作編譯期常量,而且沒有嚴重差別。VALUE_THREE是一種加倍典范的對常量停止界說的方法:界說為public,可以被任何人拜訪;界說為static,則強調只要一份;界說為final,這解釋它是個常量。請留意帶有恆定初始值的final static根本類型全用年夜寫字母定名,而且字母與字母之間用下劃線離隔。

我們不克不及由於某些數據是final的就以為在編譯時可以曉得它的值。在運轉時應用隨機數來初始化i4和INT_5的值解釋了這一點。實例中fd1和fd2中i4的值是獨一的,每次都邑被初始化為15,13。INT_5的值是弗成以經由過程創立第二個FinalData對象加以轉變的。這是由於他是static的,在裝載類時(也就是第一次創立這個類對象時)曾經被初始化,而不是每次創立都初始化。

java或許生成"空白final",所謂空白final是指被聲明為final但又未給初值的域。不管甚麼情形下編譯器都邑包管final域在應用前初始化。但空白final在final的應用上供給了很年夜的靈巧性,為此,一個final域可以依據某些對象有所分歧,卻又堅持恆定不變的特征。上面的事例解釋了一點:

package finalPackage;
class Poppet {
  private int i;
  Poppet(int ii) {
    i = ii;
  }
  public int getI() {
    return i;
  }
  public void setI(int i) {
    this.i = i;
  }
}
/**
 * 空白final
 * @author Administrator
 * 所謂空白final是指被聲明為final但又未給初值的域。不管甚麼情形下編譯器都邑包管final域在應用前初始化。
 */
public class BlankFinal {
  private final int i = 0; // Initialized final
  private final int j; // Blank final
  private final Poppet p; // Blank final reference
  // Blank finals MUST be initialized in the constructor:
  public BlankFinal() {
    j = 1; // Initialize blank final
    p = new Poppet(1); // Initialize blank final reference
  }
  public BlankFinal(int x) {
    j = x; // Initialize blank final
    p = new Poppet(x); // Initialize blank final reference
  }
  public static void main(String[] args) {
    BlankFinal b1=new BlankFinal();
    BlankFinal b2=new BlankFinal(47);
    System.out.println("b1.j="+b1.j+"\t\t b1.p.i="+b1.p.getI());
    System.out.println("b2.j="+b2.j+"\t\t b2.p.i="+b2.p.getI());
  }
  /**
   * 輸入成果:
   * b1.j=1     b1.p.i=1
   * b2.j=47     b2.p.i=47
   */
} 

final參數

java中或許將參數列表中的參數以聲明的方法聲指明為final。這意味著你無發轉變參數所指向的對象。例如:

package finalPackage;
class Gizmo {
  public void spin(String temp) {
    System.out.println(temp+" Method call Gizmo.spin()");
  }
}
/**
 * final參數
 * @author Administrator
 * 假如將參數列表中的參數指明為final,這意味著你無發轉變參數所指向的對象的援用。
 */
public class FinalArguments {
  void with(final Gizmo g) {
    // ! g = new Gizmo(); // Illegal -- g is final
  }
  void without(Gizmo g) {
    g = new Gizmo(); // OK -- g not final
    g.spin("without");
  }
  // void f(final int i) { i++; } // Can't change
  // You can only read from a final primitive:
  int g(final int i) {
    return i + 1;
  }
  public static void main(String[] args) {
    FinalArguments bf = new FinalArguments();
    bf.without(null);
    bf.with(null);
    System.out.println("bf.g(10)="+bf.g(10));
  }
  /**
   * 輸入成果:
   * withoutMethod call Gizmo.spin()
   * bf.g(10)=11
   */
} 

應用final辦法有兩個緣由。第一個緣由是把辦法鎖定,以避免任何繼續它的類修正它的寄義。這是出於設計的斟酌:想要確保在繼續中應用的辦法堅持不變,而且不會被籠罩。

曩昔建議應用final辦法的第二個緣由是效力。在java的晚期完成中,假如將一個辦法指明為final,就是贊成編譯器將針對該辦法的一切挪用都轉為內嵌挪用。當編譯器發明一個final辦法挪用敕令時,它會依據本身的謹嚴斷定,跳過拔出法式代碼這類正常的挪用方法而履行辦法挪用機制(將參數壓入棧,跳至辦法代碼處履行,然後跳回並清算棧中的參數,處置前往值),而且以辦法體中的現實代碼的正本來取代辦法挪用。這將清除辦法挪用的開支。固然,假如一個辦法很年夜,你的法式代碼會收縮,因此能夠看不到內嵌所帶來的機能上的進步,由於所帶來的機能會消費於辦法內的時光量而被縮減。

在比來的java版本中,虛擬機(特殊是hotspot技巧)可以探測到這些情形,並優化去失落這些效力反而下降的額定的內嵌挪用,是以不再須要應用final辦法來停止優化了。現實上,這類做法正逐步遭到勸止。在應用java se5/6時,應當讓編譯器和JVM行止理效力成績,只要在想明白制止籠罩式,才將辦法設置為final的。

final和private症結字

類中的一切private辦法都是隱式的制訂為final的。因為你沒法拜訪private辦法你也就沒法籠罩它。可以對private辦法添加final潤飾詞,但這毫有意義。例如:

package finalPackage;
/**
 * final和private症結字 
 * 
 * 類中的一切private辦法都是隱式的制訂為final的。
 * 因為你沒法拜訪private辦法,所以你也就沒法籠罩它。
 * 可以對private辦法添加final潤飾詞,但這毫有意義。
 */
class WithFinals {
  // Identical to "private" alone:
  private final void f() {
    System.out.println("WithFinals.f()");
  }
  // Also automatically "final":
  private void g() {
    System.out.println("WithFinals.g()");
  }
}
class OverridingPrivate extends WithFinals {
  private final void f() {
    System.out.println("OverridingPrivate.f()");
  }
  private void g() {
    System.out.println("OverridingPrivate.g()");
  }
}
class OverridingPrivate2 extends OverridingPrivate {
  public final void f() {
    System.out.println("OverridingPrivate2.f()");
  }
  public void g() {
    System.out.println("OverridingPrivate2.g()");
  }
}
public class OverideFinal {
  public static void main(String[] args) {
    WithFinals w1 = new WithFinals();
    // ! w1.f(); //Error,沒法拜訪公有辦法
    // ! w1.g(); //Error,沒法拜訪公有辦法
    OverridingPrivate w2 = new OverridingPrivate();
    // ! w2.f(); //Error,沒法拜訪公有辦法
    // ! w2.g(); //Error,沒法拜訪公有辦法
    OverridingPrivate2 w3 = new OverridingPrivate2();
    w3.f();
    w3.g();
  }
  /**
   * 輸入成果:
   * OverridingPrivate2.f()
   * OverridingPrivate2.g()
   */
}

"籠罩"只要在某辦法是基類接口的一部門時才會產生。即,必需將一個對象向上轉型為它的基類並挪用雷同的辦法。假如某辦法是private的,它就不是基類接口的一部門。它僅是一些隱蔽於類中的法式代碼,假如一個基類中存在某個private辦法,在派生類中以雷同的稱號創立一個public,protected或包拜訪權限辦法的話,該辦法只不外是與基類中的辦法有雷同的稱號罷了,並沒有籠罩基類辦法。因為private辦法沒法觸及並且能有用隱蔽,所以除把它算作是由於它所歸屬的類的組織構造的緣由而存在外,其他任何事物都不須要斟酌它。

final 類

當將類界說為final時,就注解了你不盤算繼續該類,並且也不准他人如許做。換句話說,出於某種斟酌,你對該類的設計永不須要做任何更改,或許出於平安的斟酌,你不願望他有子類。例如:

package finalPackage;
class SmallBrain {
}
final class Dinosaur {
  int i = 7;
  int j = 1;
  SmallBrain x = new SmallBrain();
  void f() {
    System.out.println("Dinosaur.f()");
  }
}
// ! class Further extends Dinosaur {}
// error: Cannot extend final class 'Dinosaur'
/**
 * final 類
 * 
 * final類中的屬性可以選擇能否界說為final
 * final類中的辦法都隱式的制訂為final辦法,是以你沒法籠罩他們
 */
public class Jurassic {
  public static void main(String[] args) {
    Dinosaur n = new Dinosaur();
    n.f();
    n.i = 40;
    n.j++;
    System.out.println("n.i="+n.i);
    System.out.println("n.j="+n.j);
  }
  /**
   * 輸入成果為:
   * Dinosaur.f()
   * n.i=40
   * n.j=2
   */
}

請留意,final類的域可以依據小我的志願選擇是或不是final。豈論類能否被界說為final,雷同的規矩異樣實用於界說為final的域。但是,因為final是沒法繼續的,所以被final潤飾的類中的辦法都隱式的制訂為fianl,由於你沒法籠罩他們。在fianl類中可以給辦法添加final,但這不會發生任何意義。

結論:

依據法式高低文情況,Java症結字final有“這是沒法轉變的”或許“終態的”寄義,它可以潤飾非籠統類、非籠統類成員辦法和變量。你能夠出於兩種懂得而須要阻攔轉變:設計或效力。
final類不克不及被繼續,沒有子類,final類中的辦法默許是final的。
final辦法不克不及被子類的辦法籠罩,但可以被繼續。
final成員變量表現常量,只能被賦值一次,賦值後值不再轉變。
final不克不及用於潤飾結構辦法。
留意:父類的private成員辦法是不克不及被子類辦法籠罩的,是以private類型的辦法默許是final類型的。

願望本文所述對年夜家Java法式設計有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved