java final keyword

?? 依據上下文環境,java的keywordfinal也存在著細微的差別,但通常指的是“這是無法改變的。”不想改變的理由由兩種:一種是效率,還有一種是設計。因為兩個原因相差非常遠,所以關鍵子final可能被吳用。

?? 接下來介紹一下使用到fianl的三中情況:數據,方法,類。

??

?? final數據

???很多編程語言都有某種方法,來向編譯器告知一塊數據是恒定不變的。有時數據的恒定不變是非常實用的,比如:

1,一個編譯時恒定不變的常量

2,一個在執行時初始化,而你不希望它被改變。

?? 對于編譯期常量的這樣的情況,編譯器能夠將該常量值代入不論什么可能用到它的計算式中,也就是說,能夠在編譯期就執行計算式,這減輕了一些執行時的負擔。在java中,這類常量必須是基本類型,而且以final表示。在對這個常量定義時,必須進行賦值。

?? 一個即是static又是fianl的域僅僅占一段不能改變的存儲空間。

?? 當final應用于對象引用時,而不是基本類型時,其含義有些讓人疑惑。對基本類型使用fianl不能改變的是他的數值。而對于對象引用,不能改變的是他的引用,而對象本身是能夠改動的。一旦一個final引用被初始化指向一個對象,這個引用將不能在指向其它對象。java并未提供對不論什么對象恒定不變的支持。這一限制也通用適用于數組,它也是對象。

?? 以下的事例示范fianl域的情況。注意,依據慣例,即是static又是fianl的域(即編譯器常量)將用大寫表示,并用下劃切割個單詞:

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 */

???? 因為valueOne和VALUE_TWO都是帶有編譯時數值的fianl基本類型,所以它們二者均能夠用作編譯期常量,而且沒有重大差別。VALUE_THREE是一種更加典型的對常量進行定義的方式:定義為public,能夠被不論什么人訪問;定義為static,則強調僅僅有一份;定義為fianl,這說明它是個常量。請注意帶有恒定初始值(即,編譯期常量)的final static基本類型全用大寫字母命名,而且字母與字母之間用下劃線隔開。

?? 我們不能由于某些數據是fianl的就覺得在編譯時能夠知道它的值。在執行時使用隨機數來初始化i4和INT_5的值叫說明了這一點。事例部分也展示了將fianl數據定義為static和非static的差別。此差別僅僅有當數值在執行時內被初始化時才會顯現,這是由于在編譯器對編譯時的數值一視同仁(而且他們可能由于優化而消失)。當執行時會看見這個差別。請注意,在此fd1和fd2中i4的值是唯一的,每次都會被初始化為15,13。INT_5的值是不能夠通過創建第二個FinalData對象加以改變的。這是由于他是static的,在裝載類時(也就是第一次創建這個類對象時)已經被初始化,而不是每次創建都初始化。

???


假設看上面的事例來理解我標記顏色的的部分有點困難的話,請看以下的事例:

???

?public class B3 { static Random r =new Random(12); final int int1= r.nextInt(100);//產生0-99的隨機數 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;//錯誤的賦值 System.out.println("int1:"+b2.int1+" INT_2:"+b2.INT_2); } }

啟動main()先運行的是B3 b1=new B3();,創建B3的第一個對象,這將會先初始化static final int INT_2= r.nextInt(100);,然后是初始化final int int1= r.nextInt(100);,所以第一條輸出語句的結果是int1:12??? INT_2:66。接下來創建B3的第二個對象,這也會導致B3類中成員的初始化,但static final int INT_2= r.nextInt(100);不會在被初始化,為什么前面已經提過。輸出的結果是int1:56??? INT_2:66。兩次的輸出INT_2的值都是一樣的。

?? 在說回我們的第一個事例,V1到VAL_3說明final引用的意義。正如在main()方法中看見的,能夠改變對象數組a的值,但不能將a的引用指向還有一個對象。看起來使基本類型成為fianl比引用類型成為final的用處大。

??? java或許生成"空白final",所謂空白final是指被聲明為final但又未給初值的域。不管什么情況下編譯器都會保證final域在使用前初始化。但空白final在fianl的使用上提供了非常大的靈活性,為此,一個fianl域能夠依據某些對象有所不同,卻又保持恒定不變的特性。以下的事例說明了一點。

?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 參數

????? java中或許將參數列表中的參數以聲明的方式聲指明為final。這意味著你無發改變參數所指向的對象。

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()展示了基本類型的參數被指定為final是所出現的結果:你能夠讀參數,但不能改動參數。這一特性僅僅要用來向匿名內部類傳遞數據。

final 方法

?? 使用final方法有兩個原因。第一個原因是把方法鎖定,以防止不論什么繼承它的類改動它的含義。這是出于設計的考慮:想要確保在繼承中使用的方法保持不變,而且不會被覆蓋。

?? 過去建議使用final方法的第二個原因是效率。在java的早期實現中,假設將一個方法指明為fianl,就是允許編譯器將針對該方法的全部調用都轉為內嵌調用。當編譯器發現一個final方法調用命令時,它會依據自己的慎重推斷,跳過插入程序代碼這樣的正常的調用方式而運行方法調用機制(將參數壓入棧,跳至方法代碼處運行,然后跳回并清理棧中的參數,處理返回值),而且以方法體中的實際代碼的副本來取代方法調用。這將消除方法調用的開銷。當然,假設一個方法非常大,你的程序代碼會膨脹,因而可能看不到內嵌所帶來的性能上的提高,由于所帶來的性能會花費于方法內的時間量而被縮減。

??? 上面標顏色的地方不太懂。不知道那位看過Java編程思想和知道的高人給解釋解釋。

??? 在最進的java版本號中,虛擬機(特別是hotspot技術)能夠探測到這些情況,并優化去掉這些效率反而減少的額外的內嵌調用,因此不再須要使用final方法來進行優化了。其實,這樣的做法正逐漸受到勸阻。在使用java se5/6時,應該讓編譯器和JVM去處理效率問題,僅僅有在想明白禁止覆蓋式,才將方法設置為fianl的。

??? final和privatekeyword

???類中的全部private方法都是隱式的制定為final的。因為你無法訪問private方法你也就無法覆蓋它。能夠對private方法加入�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()"); } }

???? "覆蓋"僅僅有在某方法是基類接口的一部分時才會發生。即,必須將一個對象向上轉型為它的基類并條用同樣的方法。假設某方法是private的,它就不是基類接口的一部分。它僅是一些隱藏于類中的程序代碼,假設一個基類中存在某個private方法,在派生類中以同樣的名稱創建一個public,protected或包訪問權限方法的話,該方法僅僅只是是與基類中的方法有同樣的名稱而已,并沒有覆蓋基類方法。由于private方法無法觸及且有非常好的隱藏性,所以把它看成是由于他所屬類的組織結的原因而存在外,其它不論什么事物都不用考慮。

??? final 類

??? 當將類定義為final時,就表明了你不打算繼承該類,并且也不或許別人這樣做。換句話說,出于某種考慮,你對該類的設計永不須要做不論什么變動,或者出于安全的考慮,你不希望他有子類。

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++; } }

??? 請注意,final類的域能夠依據個人的意愿選擇是或不是final。不論類是否被定義為final,相同的規則相同適用于定義為final的域。然而,由于final是無法繼承的,所以被final修飾的類中的方法都隱式的制定為fianl,由于你無法覆蓋他們。在fianl類中能夠給方法加入�final,但這不會產生不論什么意義。

轉載于:https://www.cnblogs.com/hrhguanli/p/4011387.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/375580.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/375580.shtml
英文地址,請注明出處:http://en.pswp.cn/news/375580.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

聽GPT 講Rust源代碼--src/tools(24)

File: rust/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs 在Rust源代碼中的rust/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs文件是Clippy項目的一個規則&#xff0c;用于檢查可能是誤用或錯誤的Box引用情況。 Rust中的Box是一個堆分配的值的所有權…

遞歸乘法

遞歸乘法。 寫一個遞歸函數&#xff0c;不使用 * 運算符&#xff0c; 實現兩個正整數的相乘。可以使用加號、減號、位移&#xff0c;但要吝嗇一些。 示例1: 輸入&#xff1a;A 1, B 10輸出&#xff1a;10示例2: 輸入&#xff1a;A 3, B 4輸出&#xff1a;12提示: 保證乘法…

Building a RESTful Web Service

http://spring.io/guides/gs/rest-service/ Should shutdown tomcat service first , and then java -jar *.jar轉載于:https://www.cnblogs.com/churuosi/p/4774151.html

IOS的各種手勢

轉自http://blog.csdn.net/likendsl/article/details/7554150 一、概述 iPhone中處理觸摸屏的操作&#xff0c;在3.2之前是主要使用的是由UIResponder而來的如下4種方式&#xff1a; - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesCancell…

duilib獲取字符串的像素長

CDuiString m_test_string _T("測試字符串")HDC m_hDc m_pm.GetPaintDC();// 100 是xml中配置的字體的編號HFONT hFont m_pm.GetFont(100);::SelectObject(m_hDc, hFont);SIZE size;GetTextExtentPoint32(m_hDc, m_test_string, i, &size);return size.cxThe …

(轉)rvm安裝與常用命令

rvm是一個命令行工具&#xff0c;可以提供一個便捷的多版本ruby環境的管理和切換。 https://rvm.io/ 如果你打算學習ruby/rails, rvm是必不可少的工具之一。 這里所有的命令都是再用戶權限下操作的&#xff0c;任何命令最好都不要用sudo. rvm安裝 $ curl -L get.rvm.io | bash …

Symfony2 EventDispatcher組件

一個插件系統中&#xff0c;A插件在不影響其它插件的前提下&#xff0c;添加新的方法&#xff0c;或者在一個方法運行前做一些準備工作&#xff0c;通過繼承來實現擴展是很不容易的&#xff0c;由于插件之間的關聯關系&#xff0c;A插件的改變也會使得關聯的插件被動的修改。Sy…

【轉】漫談ANN(2):BP神經網絡

上一次我們講了M-P模型&#xff0c;它實際上就是對單個神經元的一種建模&#xff0c;還不足以模擬人腦神經系統的功能。由這些人工神經元構建出來的網絡&#xff0c;才能夠具有學習、聯想、記憶和模式識別的能力。BP網絡就是一種簡單的人工神經網絡。我們的第二話就從BP神經網絡…

給定一個值S,在有序數組中找出兩個元素A和B,使 A+B = S.

在網上看到過一個面試題&#xff0c;感覺挺有意思&#xff0c;看別人的代碼寫的邏輯不夠謹慎&#xff0c;重寫了一個&#xff0c;較真了又。。。 package com.array7.algorithm;public class AlgorithmTest {public static void main(String[] args) {int[] arr {2 ,4 ,5 ,8 ,…

二叉樹的最小深度

給定一個二叉樹&#xff0c;找出其最小深度。 最小深度是從根節點到最近葉子節點的最短路徑上的節點數量。 說明: 葉子節點是指沒有子節點的節點。 示例: 給定二叉樹[3,9,20,null,null,15,7] 3/ \9 20/ \15 7返回它的最小深度 2. c 廣度優先 /*** Definition for a b…

(轉)會議期刊論文發表介紹(計算機科學領域)

轉自&#xff1a;http://blog.csdn.net/babyfacer/archive/2009/07/25/4377552.aspx 一、計算機科學期刊介紹計算機科學的publication最大特點在于&#xff1a;極度重視會議&#xff0c;而期刊則通常只用來做re- publication。大部分期刊文章都是會議論文的擴展版&#xff0c;首…

笑男手札:SharePoint 2013 單一服務器場環境恢復數據庫內容

SharePoint 2013 單一服務器場環境恢復數據庫內容 笑男的公司服務很多客戶&#xff0c;當然&#xff0c;這些客戶都很挑剔&#xff0c;所以一般情況下生產&#xff08;Prod&#xff09;環境的服務是不能停的。 當然&#xff0c;如果你將包含相同網站集的數據庫連接到同一個服務…

數組中數字出現的次數

一個整型數組 nums 里除兩個數字之外&#xff0c;其他數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。要求時間復雜度是O(n)&#xff0c;空間復雜度是O(1)。 示例 1&#xff1a; 輸入&#xff1a;nums [4,1,4,6] 輸出&#xff1a;[1,6] 或 [6,1]示例 2&#xff1a;…

【轉】String Date Calendar之間的轉換

1.Calendar 轉化 String Calendar calendat Calendar.getInstance(); SimpleDateFormat sdf new SimpleDateFormat("yyyy-MM-dd"); String dateStr sdf.format(calendar.getTime()); 2.String 轉化Calendar String str"2012-5-27"; SimpleDateFormat sd…

圖解 深入淺出 JavaWeb:Servlet 再說幾句

Writer &#xff1a;BYSocket&#xff08;泥沙磚瓦漿木匠&#xff09; 微 博&#xff1a;BYSocket 豆 瓣&#xff1a;BYSocket FaceBook&#xff1a;BYSocket Twitter &#xff1a;BYSocket 上一篇的《 Servlet必會必知 》受到大家一致好評 — (感謝 讀…

react.js 從零開始(五)React 中事件的用法

事件系統 虛擬事件對象 事件處理器將會傳入虛擬事件對象的實例&#xff0c;一個對瀏覽器本地事件的跨瀏覽器封裝。它有和瀏覽器本地事件相同的屬性和方法&#xff0c;包括 stopPropagation() 和 preventDefault()&#xff0c;但是沒有瀏覽器兼容問題。 如果因為一些因素&#x…

乘積的最大子數組

給你一個整數數組 nums &#xff0c;請你找出數組中乘積最大的連續子數組&#xff08;該子數組中至少包含一個數字&#xff09;&#xff0c;并返回該子數組所對應的乘積。 示例 1: 輸入: [2,3,-2,4] 輸出: 6 解釋: 子數組 [2,3] 有最大乘積 6。示例 2: 輸入: [-2,0,-1] 輸出…

javascript new

1. 僅function可以使用new 2. function使用new時&#xff0c;會拷貝function中this的內容給新對象&#xff0c;并將function的prototype指向新對象&#xff08;如果該function沒有prototype&#xff0c;則指向Object的prototype&#xff09; 注&#xff1a;function本身不是Obj…

!+\v1 用來“判斷瀏覽器類型”還是用來“IE判斷版本”的問題!

這種寫法是利用各瀏覽器對轉義字符"\v"的理解不同來判斷瀏覽器類型。在IE中&#xff0c;"\v"沒有轉義&#xff0c;得到的結果為"v"。而在其他瀏覽器中"\v"表示一個垂直制表符&#xff0c;所以ie解析的"\v1" 為 "v1&quo…

三個數的最大乘積

給定一個整型數組&#xff0c;在數組中找出由三個數組成的最大乘積&#xff0c;并輸出這個乘積。 示例 1: 輸入: [1,2,3] 輸出: 6示例 2: 輸入: [1,2,3,4] 輸出: 24注意: 給定的整型數組長度范圍是[3,104]&#xff0c;數組中所有的元素范圍是[-1000, 1000]。 輸入的數組中任…