1. 程式人生 > >記錄自己的第一次面試(網易java後臺)

記錄自己的第一次面試(網易java後臺)

**1.java基本資料型別大小**

1)整數:包括 byte,short, int,long

2)浮點型:float,double 

3)字元:char 

4)布林:boolean

-byte 8-bit -128 +127

- short 16-bit -32768 +32767

-int 32-bit -2^31 +2^31-1

-long 64-bit -2^63 +2^63-1

-float 32-bit IEEE754 IEEE754

-double 64-bit IEEE754 IEEE754

-char 16-bit 0 65535

-boolean true false

2.資料

說白了,索引問題就是一個查詢問題。。。

資料庫索引,是資料庫管理系統中一個排序的資料結構,以協助快速查詢、更新資料庫表中資料。索引的實現通常使用B樹及其變種B+樹

在資料之外,資料庫系統還維護著滿足特定查詢演算法的資料結構,這些資料結構以某種方式引用(指向)資料,這樣就可以在這些資料結構上實現高階查詢演算法。這種資料結構,就是索引。

為表設定索引要付出代價的:一是增加了資料庫的儲存空間二是在插入和修改資料時要花費較多的時間(因為索引也要隨之變動)


上圖展示了一種可能的索引方式。左邊是資料表,一共有兩列七條記錄,最左邊的是資料記錄的實體地址(注意邏輯上相鄰的記錄在磁碟上也並不是一定物理相鄰的)。為了加快Col2的查詢,可以維護一個右邊所示的二叉查詢樹,每個節點分別包含索引鍵值和一個指向對應資料記錄實體地址的指標,這樣就可以運用二叉查詢在O(log2

n)的複雜度內獲取到相應資料。

建立索引可以大大提高系統的效能。

第一,通過建立唯一性索引,可以保證資料庫表中每一行資料的唯一性。

第二,可以大大加快資料的檢索速度,這也是建立索引的最主要的原因。

第三,可以加速表和表之間的連線,特別是在實現資料的參考完整性方面特別有意義。

第四,在使用分組和排序子句進行資料檢索時,同樣可以顯著減少查詢中分組和排序的時間。

第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的效能。 

也許會有人要問:增加索引有如此多的優點,為什麼不對錶中的每一個列建立一個索引呢?因為,增加索引也有許多不利的方面。

第一,建立索引和維護索引要耗費時間,這種時間隨著資料量的增加而增加。

第二,索引需要佔物理空間,除了資料表佔資料空間之外,每一個索引還要佔一定的物理空間,如果要建立聚簇索引,那麼需要的空間就會更大。

第三,當對錶中的資料進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了資料的維護速度。

索引是建立在資料庫表中的某些列的上面。在建立索引的時候,應該考慮在哪些列上可以建立索引,在哪些列上不能建立索引。

一般來說,應該在這些列上建立索引:

在經常需要搜尋的列上,可以加快搜索的速度;

在作為主鍵的列上,強制該列的唯一性和組織表中資料的排列結構;

在經常用在連線的列上,這些列主要是一些外來鍵,可以加快連線的速度;

在經常需要根據範圍進行搜尋的列上建立索引,因為索引已經排序,其指定的範圍是連續的;

在經常需要排序的列上建立索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;

在經常使用在WHERE子句中的列上面建立索引,加快條件的判斷速度。

同樣,對於有些列不應該建立索引。一般來說,不應該建立索引的的這些列具有下列特點:

第一,對於那些在查詢中很少使用或者參考的列不應該建立索引。這是因為,既然這些列很少使用到,因此有索引或者無索引,並不能提高查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。

第二,對於那些只有很少資料值的列也不應該增加索引。這是因為,由於這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的資料行佔了表中資料行的很大比例,即需要在表中搜索的資料行的比例很大。增加索引,並不能明顯加快檢索速度。

第三,對於那些定義為text, image和bit資料型別的列不應該增加索引。這是因為,這些列的資料量要麼相當大,要麼取值很少。

第四,當修改效能遠遠大於檢索效能時,不應該建立索引。這是因為,修改效能和檢索效能是互相矛盾的。當增加索引時,會提高檢索效能,但是會降低修改效能。當減少索引時,會提高修改效能,降低檢索效能。因此,當修改效能遠遠大於檢索效能時,不應該建立索引。

根據資料庫的功能,可以在資料庫設計器中建立三種索引:唯一索引、主鍵索引和聚集索引

唯一索引

唯一索引是不允許其中任何兩行具有相同索引值的索引。

當現有資料中存在重複的鍵值時,大多數資料庫不允許將新建立的唯一索引與表一起儲存。資料庫還可能防止新增將在表中建立重複鍵值的新資料。例如,如果在employee表中職員的姓(lname)上建立了唯一索引,則任何兩個員工都不能同姓。 主鍵索引 資料庫表經常有一列或列組合,其值唯一標識表中的每一行。該列稱為表的主鍵。 在資料庫關係圖中為表定義主鍵將自動建立主鍵索引,主鍵索引是唯一索引的特定型別。該索引要求主鍵中的每個值都唯一。當在查詢中使用主鍵索引時,它還允許對資料的快速訪問。 聚集索引 在聚集索引中,表中行的物理順序與鍵值的邏輯(索引)順序相同。一個表只能包含一個聚集索引。

如果某索引不是聚集索引,則表中行的物理順序與鍵值的邏輯順序不匹配。與非聚集索引相比,聚集索引通常提供更快的資料訪問速度。

區域性性原理與磁碟預讀

由於儲存介質的特性,磁碟本身存取就比主存慢很多,再加上機械運動耗費,磁碟的存取速度往往是主存的幾百分分之一,因此為了提高效率,要儘量減少磁碟I/O。為了達到這個目的,磁碟往往不是嚴格按需讀取,而是每次都會預讀,即使只需要一個位元組,磁碟也會從這個位置開始,順序向後讀取一定長度的資料放入記憶體。這樣做的理論依據是電腦科學中著名的區域性性原理當一個數據被用到時,其附近的資料也通常會馬上被使用。程式執行期間所需要的資料通常比較集中。

由於磁碟順序讀取的效率很高(不需要尋道時間,只需很少的旋轉時間),因此對於具有區域性性的程式來說,預讀可以提高I/O效率。

預讀的長度一般為頁(page)的整倍數。頁是計算機管理儲存器的邏輯塊,硬體及作業系統往往將主存和磁碟儲存區分割為連續的大小相等的塊,每個儲存塊稱為一頁(在許多作業系統中,頁得大小通常為4k),主存和磁碟以頁為單位交換資料。當程式要讀取的資料不在主存中時,會觸發一個缺頁異常,此時系統會向磁碟發出讀盤訊號,磁碟會找到資料的起始位置並向後連續讀取一頁或幾頁載入記憶體中,然後異常返回,程式繼續執行。

B-/+Tree索引的效能分析

到這裡終於可以分析B-/+Tree索引的效能了。

上文說過一般使用磁碟I/O次數評價索引結構的優劣。先從B-Tree分析,根據B-Tree的定義,可知檢索一次最多需要訪問h個節點。資料庫系統的設計者巧妙利用了磁碟預讀原理,將一個節點的大小設為等於一個頁,這樣每個節點只需要一次I/O就可以完全載入。為了達到這個目的,在實際實現B-Tree還需要使用如下技巧:

每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也儲存在一個頁裡,加之計算機儲存分配都是按頁對齊的,就實現了一個node只需一次I/O。

B-Tree中一次檢索最多需要h-1次I/O(根節點常駐記憶體),漸進複雜度為O(h)=O(logdN)。一般實際應用中,出度d是非常大的數字,通常超過100,因此h非常小(通常不超過3)。

而紅黑樹這種結構,h明顯要深的多。由於邏輯上很近的節點(父子)物理上可能很遠,無法利用區域性性,所以紅黑樹的I/O漸進複雜度也為O(h),效率明顯比B-Tree差很多。

綜上所述,用B-Tree作為索引結構效率是非常高的。

應該花時間學習B-樹和B+樹資料結構

=============================================================================================================

1)B樹

B樹中每個節點包含了鍵值和鍵值對於的資料物件存放地址指標,所以成功搜尋一個物件可以不用到達樹的葉節點。

成功搜尋包括節點內搜尋和沿某一路徑的搜尋,成功搜尋時間取決於關鍵碼所在的層次以及節點內關鍵碼的數量。

在B樹中查詢給定關鍵字的方法是:首先把根結點取來,在根結點所包含的關鍵字K1,…,kj查詢給定的關鍵字(可用順序查詢或二分查詢法),若找到等於給定值的關鍵字,則查詢成功;否則,一定可以確定要查的關鍵字在某個Ki或Ki+1之間,於是取Pi所指的下一層索引節點塊繼續查詢,直到找到,或指標Pi為空時查詢失敗。

2)B+樹

B+樹非葉節點中存放的關鍵碼並不指示資料物件的地址指標,非也節點只是索引部分。所有的葉節點在同一層上,包含了全部關鍵碼和相應資料物件的存放地址指標,且葉節點按關鍵碼從小到大順序連結。如果實際資料物件按加入的順序儲存而不是按關鍵碼次數儲存的話,葉節點的索引必須是稠密索引,若實際資料儲存按關鍵碼次序存放的話,葉節點索引時稀疏索引。

B+樹有2個頭指標,一個是樹的根節點,一個是最小關鍵碼的葉節點。

所以 B+樹有兩種搜尋方法:

一種是按葉節點自己拉起的連結串列順序搜尋。

一種是從根節點開始搜尋,和B樹類似,不過如果非葉節點的關鍵碼等於給定值,搜尋並不停止,而是繼續沿右指標,一直查到葉節點上的關鍵碼。所以無論搜尋是否成功,都將走完樹的所有層。

B+ 樹中,資料物件的插入和刪除僅在葉節點上進行。

這兩種處理索引的資料結構的不同之處:
a,B樹中同一鍵值不會出現多次,並且它有可能出現在葉結點,也有可能出現在非葉結點中。而B+樹的鍵一定會出現在葉結點中,並且有可能在非葉結點中也有可能重複出現,以維持B+樹的平衡。
b,因為B樹鍵位置不定,且在整個樹結構中只出現一次,雖然可以節省儲存空間,但使得在插入、刪除操作複雜度明顯增加。B+樹相比來說是一種較好的折中。
c,B樹的查詢效率與鍵在樹中的位置有關,最大時間複雜度與B+樹相同(在葉結點的時候),最小時間複雜度為1(在根結點的時候)。而B+樹的時候複雜度對某建成的樹是固定的。

3.Java容器

JAVA的容器---List,Map,Set 

List介面

ArrayList

        ArrayList其實就相當於順式儲存,它包裝了一個數組 Object[],當例項化一個ArrayList時,一個數組也被例項化,當向ArrayList中新增物件時,陣列的大小也相應的改變。這樣就帶來以下有特點:
       快速隨即訪問,你可以隨即訪問每個元素而不用考慮效能問題,通過呼叫get(i)方法來訪問下標為i的陣列元素。
       向其中新增物件速度慢,當你建立陣列時並不能確定其容量,所以當改變這個陣列時就必須在記憶體中做很多事情。
       操作其中物件的速度慢,當你要向陣列中任意兩個元素中間新增物件時,陣列需要移動所有後面的物件。

LinkedList

        LinkedList相當於鏈式儲存,使用雙向連結串列,它是通過節點直接彼此連線來實現的。每一個節點都包含前一個節點的引用,後一個節點的引用和節點儲存的值。當一個新節點插入時,只需要修改其中保持先後關係的節點的引用即可,當刪除記錄時也一樣。這樣就帶來以下有特點:
       操作其中物件的速度快,只需要改變連線,新的節點可以在記憶體中的任何地方。
       不能隨即訪問,雖然存在get()方法,但是這個方法是通過遍歷接點來定位的,所以速度慢。

Set介面

      Set是一種不包含重複的元素的Collection,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。
      Set的建構函式有一個約束條件,傳入的Collection引數不能包含重複的元素。
      Set容器類主要有HashSet和TreeSet升序等。

HashSet

       此類實現 Set 介面,由雜湊表(實際上是一個 HashMap 例項)支援。它不保證 set 的迭代順序;特別是它不保證該順序恆久不變。此類允許使用 null 元素。

Map介面

        值得注意的是Map沒有繼承Collection介面,Map介面是提供key到value的對映。一個Map中不能包含相同的key,每個key只能對映一個value。即是一一對映,Map介面提供3種集合的檢視,Map的內容可以被當作一組key集合,一組value集合,或者一組key-value對映。
        Map介面的實現類主要是包括HashMap和TreeMap等。

HaspMap

         新增資料使用put(key, value),取出資料使用get(key),HashMap是允許null,即null value和null key。但是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap的容量成比例。因此,如果迭代操作的效能相當重要的話,不要將HashMap的初始化容量設得過高,或者load factor過低。 介紹一下volatile關鍵字

volatile關鍵字的兩層語義

  一旦一個共享變數(類的成員變數、類的靜態成員變數)被volatile修飾之後,那麼就具備了兩層語義:

  1)保證了不同執行緒對這個變數進行操作時的可見性,即一個執行緒修改了某個變數的值,這新值對其他執行緒來說是立即可見的。

  2)禁止進行指令重排序。

  先看一段程式碼,假如執行緒1先執行,執行緒2後執行:

1 2 3 4 5 6 7 8 //執行緒1 boolean stop = false; while(!stop){ doSomething(); } //執行緒2 stop = true;

   這段程式碼是很典型的一段程式碼,很多人在中斷執行緒時可能都會採用這種標記辦法。但是事實上,這段程式碼會完全執行正確麼?即一定會將執行緒中斷麼?不一定,也許在大多數時候,這個程式碼能夠把執行緒中斷,但是也有可能會導致無法中斷執行緒(雖然這個可能性很小,但是隻要一旦發生這種情況就會造成死迴圈了)。

  下面解釋一下這段程式碼為何有可能導致無法中斷執行緒。在前面已經解釋過,每個執行緒在執行過程中都有自己的工作記憶體,那麼執行緒1在執行的時候,會將stop變數的值拷貝一份放在自己的工作記憶體當中。

  那麼當執行緒2更改了stop變數的值之後,但是還沒來得及寫入主存當中,執行緒2轉去做其他事情了,那麼執行緒1由於不知道執行緒2對stop變數的更改,因此還會一直迴圈下去。

  但是用volatile修飾之後就變得不一樣了:

  第一:使用volatile關鍵字會強制將修改的值立即寫入主存;

  第二:使用volatile關鍵字的話,當執行緒2進行修改時,會導致執行緒1的工作記憶體中快取變數stop的快取行無效(反映到硬體層的話,就是CPU的L1或者L2快取中對應的快取行無效);

  第三:由於執行緒1的工作記憶體中快取變數stop的快取行無效,所以執行緒1再次讀取變數stop的值時會去主存讀取。

  那麼線上程2修改stop值時(當然這裡包括2個操作,修改執行緒2工作記憶體中的值,然後將修改後的值寫入記憶體),會使得執行緒1的工作記憶體中快取變數stop的快取行無效,然後執行緒1讀取時,發現自己的快取行無效,它會等待快取行對應的主存地址被更新之後,然後去對應的主存讀取最新的值。

  那麼執行緒1讀取到的就是最新的正確的值。

說一下http協議


GC

手寫二分查詢