java final keyword
?? 依據(jù)上下文環(huán)境,java的keywordfinal也存在著細(xì)微的差別,但通常指的是“這是無法改變的。”不想改變的理由由兩種:一種是效率,還有一種是設(shè)計(jì)。因?yàn)閮蓚€(gè)原因相差非常遠(yuǎn),所以關(guān)鍵子final可能被吳用。
?? 接下來介紹一下使用到fianl的三中情況:數(shù)據(jù),方法,類。
??
?? final數(shù)據(jù)
???很多編程語(yǔ)言都有某種方法,來向編譯器告知一塊數(shù)據(jù)是恒定不變的。有時(shí)數(shù)據(jù)的恒定不變是非常實(shí)用的,比如:
1,一個(gè)編譯時(shí)恒定不變的常量
2,一個(gè)在執(zhí)行時(shí)初始化,而你不希望它被改變。
?? 對(duì)于編譯期常量的這樣的情況,編譯器能夠?qū)⒃摮A恐荡氩徽撌裁纯赡苡玫剿挠?jì)算式中,也就是說,能夠在編譯期就執(zhí)行計(jì)算式,這減輕了一些執(zhí)行時(shí)的負(fù)擔(dān)。在java中,這類常量必須是基本類型,而且以final表示。在對(duì)這個(gè)常量定義時(shí),必須進(jìn)行賦值。
?? 一個(gè)即是static又是fianl的域僅僅占一段不能改變的存儲(chǔ)空間。
?? 當(dāng)final應(yīng)用于對(duì)象引用時(shí),而不是基本類型時(shí),其含義有些讓人疑惑。對(duì)基本類型使用fianl不能改變的是他的數(shù)值。而對(duì)于對(duì)象引用,不能改變的是他的引用,而對(duì)象本身是能夠改動(dòng)的。一旦一個(gè)final引用被初始化指向一個(gè)對(duì)象,這個(gè)引用將不能在指向其它對(duì)象。java并未提供對(duì)不論什么對(duì)象恒定不變的支持。這一限制也通用適用于數(shù)組,它也是對(duì)象。
?? 以下的事例示范fianl域的情況。注意,依據(jù)慣例,即是static又是fianl的域(即編譯器常量)將用大寫表示,并用下劃切割個(gè)單詞:
package reusing; //: reusing/FinalData.java // The effect of final on fields. import java.util.*; import static net.mindview.util.Print.*; class Value { int i; // Package access public Value(int i) { this.i = i; } } 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]; print(fd1); print("Creating new FinalData"); FinalData fd2 = new FinalData("fd2"); print(fd1); print(fd2); } } /* Output: fd1: i4 = 15, INT_5 = 18 Creating new FinalData fd1: i4 = 15, INT_5 = 18 fd2: i4 = 13, INT_5 = 18 */
???? 因?yàn)関alueOne和VALUE_TWO都是帶有編譯時(shí)數(shù)值的fianl基本類型,所以它們二者均能夠用作編譯期常量,而且沒有重大差別。VALUE_THREE是一種更加典型的對(duì)常量進(jìn)行定義的方式:定義為public,能夠被不論什么人訪問;定義為static,則強(qiáng)調(diào)僅僅有一份;定義為fianl,這說明它是個(gè)常量。請(qǐng)注意帶有恒定初始值(即,編譯期常量)的final static基本類型全用大寫字母命名,而且字母與字母之間用下劃線隔開。
?? 我們不能由于某些數(shù)據(jù)是fianl的就覺得在編譯時(shí)能夠知道它的值。在執(zhí)行時(shí)使用隨機(jī)數(shù)來初始化i4和INT_5的值叫說明了這一點(diǎn)。事例部分也展示了將fianl數(shù)據(jù)定義為static和非static的差別。此差別僅僅有當(dāng)數(shù)值在執(zhí)行時(shí)內(nèi)被初始化時(shí)才會(huì)顯現(xiàn),這是由于在編譯器對(duì)編譯時(shí)的數(shù)值一視同仁(而且他們可能由于優(yōu)化而消失)。當(dāng)執(zhí)行時(shí)會(huì)看見這個(gè)差別。請(qǐng)注意,在此fd1和fd2中i4的值是唯一的,每次都會(huì)被初始化為15,13。INT_5的值是不能夠通過創(chuàng)建第二個(gè)FinalData對(duì)象加以改變的。這是由于他是static的,在裝載類時(shí)(也就是第一次創(chuàng)建這個(gè)類對(duì)象時(shí))已經(jīng)被初始化,而不是每次創(chuàng)建都初始化。
???
假設(shè)看上面的事例來理解我標(biāo)記顏色的的部分有點(diǎn)困難的話,請(qǐng)看以下的事例:
???
?public class B3 { static Random r =new Random(12); final int int1= r.nextInt(100);//產(chǎn)生0-99的隨機(jī)數(shù) static final int INT_2= r.nextInt(100); public static void main(String[] args) { B3 b1=new B3(); System.out.println("int1:"+b1.int1+" INT_2:"+b1.INT_2); B3 b2=new B3(); //b2.INT_2=100;//錯(cuò)誤的賦值 System.out.println("int1:"+b2.int1+" INT_2:"+b2.INT_2); } }
啟動(dòng)main()先運(yùn)行的是B3 b1=new B3();,創(chuàng)建B3的第一個(gè)對(duì)象,這將會(huì)先初始化static final int INT_2= r.nextInt(100);,然后是初始化final int int1= r.nextInt(100);,所以第一條輸出語(yǔ)句的結(jié)果是int1:12??? INT_2:66。接下來創(chuàng)建B3的第二個(gè)對(duì)象,這也會(huì)導(dǎo)致B3類中成員的初始化,但static final int INT_2= r.nextInt(100);不會(huì)在被初始化,為什么前面已經(jīng)提過。輸出的結(jié)果是int1:56??? INT_2:66。兩次的輸出INT_2的值都是一樣的。
?? 在說回我們的第一個(gè)事例,V1到VAL_3說明final引用的意義。正如在main()方法中看見的,能夠改變對(duì)象數(shù)組a的值,但不能將a的引用指向還有一個(gè)對(duì)象。看起來使基本類型成為fianl比引用類型成為final的用處大。
??? java或許生成"空白final",所謂空白final是指被聲明為final但又未給初值的域。不管什么情況下編譯器都會(huì)保證final域在使用前初始化。但空白final在fianl的使用上提供了非常大的靈活性,為此,一個(gè)fianl域能夠依據(jù)某些對(duì)象有所不同,卻又保持恒定不變的特性。以下的事例說明了一點(diǎn)。
?class Poppet { private int i; Poppet(int ii) { i = ii; } } 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) { new BlankFinal(); new BlankFinal(47); } } //
?
final 參數(shù)
????? java中或許將參數(shù)列表中的參數(shù)以聲明的方式聲指明為final。這意味著你無發(fā)改變參數(shù)所指向的對(duì)象。
class Gizmo { public void spin() {} } 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(); } // 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); } } //
方法f()g()展示了基本類型的參數(shù)被指定為final是所出現(xiàn)的結(jié)果:你能夠讀參數(shù),但不能改動(dòng)參數(shù)。這一特性僅僅要用來向匿名內(nèi)部類傳遞數(shù)據(jù)。
final 方法
?? 使用final方法有兩個(gè)原因。第一個(gè)原因是把方法鎖定,以防止不論什么繼承它的類改動(dòng)它的含義。這是出于設(shè)計(jì)的考慮:想要確保在繼承中使用的方法保持不變,而且不會(huì)被覆蓋。
?? 過去建議使用final方法的第二個(gè)原因是效率。在java的早期實(shí)現(xiàn)中,假設(shè)將一個(gè)方法指明為fianl,就是允許編譯器將針對(duì)該方法的全部調(diào)用都轉(zhuǎn)為內(nèi)嵌調(diào)用。當(dāng)編譯器發(fā)現(xiàn)一個(gè)final方法調(diào)用命令時(shí),它會(huì)依據(jù)自己的慎重推斷,跳過插入程序代碼這樣的正常的調(diào)用方式而運(yùn)行方法調(diào)用機(jī)制(將參數(shù)壓入棧,跳至方法代碼處運(yùn)行,然后跳回并清理?xiàng)V械膮?shù),處理返回值),而且以方法體中的實(shí)際代碼的副本來取代方法調(diào)用。這將消除方法調(diào)用的開銷。當(dāng)然,假設(shè)一個(gè)方法非常大,你的程序代碼會(huì)膨脹,因而可能看不到內(nèi)嵌所帶來的性能上的提高,由于所帶來的性能會(huì)花費(fèi)于方法內(nèi)的時(shí)間量而被縮減。
??? 上面標(biāo)顏色的地方不太懂。不知道那位看過Java編程思想和知道的高人給解釋解釋。
??? 在最進(jìn)的java版本號(hào)中,虛擬機(jī)(特別是hotspot技術(shù))能夠探測(cè)到這些情況,并優(yōu)化去掉這些效率反而減少的額外的內(nèi)嵌調(diào)用,因此不再須要使用final方法來進(jìn)行優(yōu)化了。其實(shí),這樣的做法正逐漸受到勸阻。在使用java se5/6時(shí),應(yīng)該讓編譯器和JVM去處理效率問題,僅僅有在想明白禁止覆蓋式,才將方法設(shè)置為fianl的。
??? final和privatekeyword
???類中的全部private方法都是隱式的制定為final的。因?yàn)槟銦o法訪問private方法你也就無法覆蓋它。能夠?qū)rivate方法加入final修飾詞,但這毫無意義。
class WithFinals { // Identical to "private" alone: private final void f() { print("WithFinals.f()"); } // Also automatically "final": private void g() { print("WithFinals.g()"); } } class OverridingPrivate extends WithFinals { private final void f() { print("OverridingPrivate.f()"); } private void g() { print("OverridingPrivate.g()"); } } class OverridingPrivate2 extends OverridingPrivate { public final void f() { print("OverridingPrivate2.f()"); } public void g() { print("OverridingPrivate2.g()"); } }
???? "覆蓋"僅僅有在某方法是基類接口的一部分時(shí)才會(huì)發(fā)生。即,必須將一個(gè)對(duì)象向上轉(zhuǎn)型為它的基類并條用同樣的方法。假設(shè)某方法是private的,它就不是基類接口的一部分。它僅是一些隱藏于類中的程序代碼,假設(shè)一個(gè)基類中存在某個(gè)private方法,在派生類中以同樣的名稱創(chuàng)建一個(gè)public,protected或包訪問權(quán)限方法的話,該方法僅僅只是是與基類中的方法有同樣的名稱而已,并沒有覆蓋基類方法。由于private方法無法觸及且有非常好的隱藏性,所以把它看成是由于他所屬類的組織結(jié)的原因而存在外,其它不論什么事物都不用考慮。
??? final 類
??? 當(dāng)將類定義為final時(shí),就表明了你不打算繼承該類,并且也不或許別人這樣做。換句話說,出于某種考慮,你對(duì)該類的設(shè)計(jì)永不須要做不論什么變動(dòng),或者出于安全的考慮,你不希望他有子類。
class SmallBrain {} final class Dinosaur { int i = 7; int j = 1; SmallBrain x = new SmallBrain(); void f() {} } //! class Further extends Dinosaur {} // error: Cannot extend final class 'Dinosaur' public class Jurassic { public static void main(String[] args) { Dinosaur n = new Dinosaur(); n.f(); n.i = 40; n.j++; } }
??? 請(qǐng)注意,final類的域能夠依據(jù)個(gè)人的意愿選擇是或不是final。不論類是否被定義為final,相同的規(guī)則相同適用于定義為final的域。然而,由于final是無法繼承的,所以被final修飾的類中的方法都隱式的制定為fianl,由于你無法覆蓋他們。在fianl類中能夠給方法加入final,但這不會(huì)產(chǎn)生不論什么意義。
轉(zhuǎn)載于:https://www.cnblogs.com/mengfanrong/p/4297540.html
總結(jié)
以上是生活随笔為你收集整理的java final keyword的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【BZOJ】【2154】Crash的数字
- 下一篇: 批处理命令 For循环命令具体解释!