1、性質不一樣html
(1)final爲關鍵字;java
(2)finalize()爲方法;ios
(3)finally爲爲區塊標誌,用於try語句中;編程
2、做用服務器
(1)final爲用於標識常量的關鍵字,final標識的關鍵字存儲在常量池中(在這裏final常量的具體用法將在下面進行介紹);架構
(2)finalize()方法在Object中進行了定義,用於在對象「消失」時,由JVM進行調用用於對對象進行垃圾回收,相似於C++中的析構函數;用戶自定義時,用於釋放對象佔用的資源(好比進行I/0操做);併發
(3)finally{}用於標識代碼塊,與try{}進行配合,不論try中的代碼執行完或沒有執行完(這裏指有異常),該代碼塊之中的程序一定會進行;函數式編程
3、final詳解函數
1定義變量高併發
1.1 final定義基本類型變量時,要求變量初始化必須在聲明時或者構造函數中,不能用於其它地方。該關鍵字定義的常量,除了初始化階段,不能更改常量的值。
1.2 final定義對象的引用,該引用的初始化與定義常量時的要求一致;該關鍵字定義的對象內容能夠改變,可是引用指向的地址不能改變;
2定義參數
若是傳入該參數定義的變量時,方法不能對該參數內容進行修改(錯誤),與定義變量的修改規則相同;java方法中傳遞基本類型時是傳值的,java方法對於對象的傳遞是傳參的;<歸根結底,java中方法的傳遞是依靠傳遞「副本」:對於基本類型,首先創建一個Copy,並將傳入的值賦值給Copy,而後對Copy進行操做;對於對象類型,首先創建一個引用Copy,並將傳入的對象引用賦值給Copy>
好比:method(final int test);
有些書上說,這裏final定義參數,尤爲是對象的參數頗有做用,不能在方法內對於對象的內容進行改變,這樣的說法是錯誤的!原來我也認爲這樣有些函數式編程的特色,不能對於對象的內容進行修改該,這裏依舊能夠對對象的內容進行修改。
??定義該參數有什麼用??
String天生就是final類型的!
3定義方法
(1)使用final關鍵字定義的方法,不能被子類繼承;
(2)容許編譯器將全部對此方法的調用轉化爲inline(行內)行爲,便可以將此方法直接複製在調用處,而不是進行例行的方法調用(保存斷點、壓棧),這樣會使程序的效率升高。可是---------若是過多的話,這樣會形成代碼膨脹,反而會影響效率,因此該方法要慎用。。
4定義類
一個任何final類沒法被任何人繼承,這也就意味着此類在一個繼承樹中是一個葉子類,而且此類被認爲是很完美的,不須要進行任何修改(總之是不推薦使用)
一、無論有木有出現異常,finally塊中代碼都會執行;
二、當try和catch中有return時,finally仍然會執行;
三、finally是在return後面的表達式運算後執行的(此時並無返回運算後的值,而是先把要返回的值保存起來,管finally中的代碼怎麼樣,返回的值都不會改變,任然是以前保存的值),因此函數返回值是在finally執行前肯定的;
四、finally中最好不要包含return,不然程序會提早退出,返回值不是try或catch中保存的返回值。
舉例:
狀況1:try{} catch(){}finally{} return;
顯然程序按順序執行。
狀況2:try{ return; }catch(){} finally{} return;
程序執行try塊中return以前(包括return語句中的表達式運算)代碼;
再執行finally塊,最後執行try中return;
finally塊以後的語句return,由於程序在try中已經return因此再也不執行。
狀況3:try{ } catch(){return;} finally{} return;
程序先執行try,若是遇到異常執行catch塊,
有異常:則執行catch中return以前(包括return語句中的表達式運算)代碼,再執行finally語句中所有代碼,
最後執行catch塊中return. finally以後也就是4處的代碼再也不執行。
無異常:執行完try再finally再return.
狀況4:try{ return; }catch(){} finally{return;}
程序執行try塊中return以前(包括return語句中的表達式運算)代碼;
再執行finally塊,由於finally塊中有return因此提早退出。
狀況5:try{} catch(){return;}finally{return;}
程序執行catch塊中return以前(包括return語句中的表達式運算)代碼;
再執行finally塊,由於finally塊中有return因此提早退出。
狀況6:try{ return;}catch(){return;} finally{return;}
程序執行try塊中return以前(包括return語句中的表達式運算)代碼;
有異常:執行catch塊中return以前(包括return語句中的表達式運算)代碼;
則再執行finally塊,由於finally塊中有return因此提早退出。
無異常:則再執行finally塊,由於finally塊中有return因此提早退出。
最終結論:任何執行try 或者catch中的return語句以前,都會先執行finally語句,若是finally存在的話。
若是finally中有return語句,那麼程序就return了,因此finally中的return是必定會被return的,
編譯器把finally中的return實現爲一個warning。
下面是個測試程序 public class FinallyTest { public static void main(String[] args) { System.out.println(new FinallyTest().test());; } static int test() { int x = 1; try { x++; return x; } finally { ++x; } } } 結果是2。
分析:
題目:輸入一個單向鏈表,輸出該鏈表中倒數第k個結點。鏈表的倒數第0個結點爲鏈表的尾指針。
分析:爲了獲得倒數第k個結點,很天然的想法是先走到鏈表的尾端,再從尾端回溯k步。但是輸入的是單向鏈表,只有從前日後的指針而沒有從後往前的指針。所以咱們須要打開咱們的思路。既然不能從尾結點開始遍歷這個鏈表,咱們仍是把思路回到頭結點上來。假設整個鏈表有n個結點,那麼倒數第k個結點是從頭結點開始的第n-k-1個結點(從0開始計數)。若是咱們可以獲得鏈表中結點的個數n,那咱們只要從頭結點開始日後走n-k-1步就能夠了。如何獲得結點數n?這個不難,只須要從頭開始遍歷鏈表,每通過一個結點,計數器加一就好了。這種思路的時間複雜度是O(n),但須要遍歷鏈表兩次。第一次獲得鏈表中結點個數n,第二次獲得從頭結點開始的第n-k-1個結點即倒數第k個結點。如 果鏈表的結點數很少,這是一種很好的方法。但若是輸入的鏈表的結點個數不少,有可能不能一次性把整個鏈表都從硬盤讀入物理內存,那麼遍歷兩遍意味着一個結 點須要兩次從硬盤讀入到物理內存。咱們知道把數據從硬盤讀入到內存是很是耗時間的操做。咱們能不能把鏈表遍歷的次數減小到1?若是能夠,將能有效地提升代碼執行的時間效率。若是咱們在遍歷時維持兩個指針,第一個指針從鏈表的頭指針開始遍歷,在第k-1步以前,第二個指針保持不動;在第k-1步開始,第二個指針也開始從鏈表的頭指針開始遍歷。因爲兩個指針的距離保持在k-1,當第一個(走在前面的)指針到達鏈表的尾結點時,第二個指針(走在後面的)指針正好是倒數第k個結點。這種思路只須要遍歷鏈表一次。對於很長的鏈表,只須要把每一個結點從硬盤導入到內存一次。所以這一方法的時間效率前面的方法要高。
#include <iostream>
#include <map>
using
namespace
std;
typedef
struct
ListNode{
int
m_nkey;
ListNode *m_pnext;
} ListNode,*Node;
int
main()
{
int
n,k;
cout<<
"The length of the list: "
<<endl;
cin>>n;
cout<<
"Which one to select(from tail): "
<<endl;
cin>>k;
Node head,tmp,last;
for
(
int
i=n;i>=1;i--)
{
tmp=
new
ListNode();
tmp->m_nkey=i;
if
(i==n)
head=tmp;
else
last->m_pnext=tmp;
tmp->m_pnext=NULL;
last=tmp;
}
Node p=head;
Node q=head;
int
i=1;
while
(p!=NULL)
{
if
(i<=k)
{
i++;
p=p->m_pnext;
}
else
{
p=p->m_pnext;
q=q->m_pnext;
}
}
cout<<
"The data is: "
<<q->m_nkey<<endl;
}
|
高併發高負載的大型網站系統架構:http://developer.51cto.com/art/200906/129475.htm
高性能高併發服務器架構:http://www.doc88.com/p-5820457828.html