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法式設計有所贊助。