2017年4月26號課堂筆記

2017年4月26號 晴 空氣質量:優html

內容:U1知識總結前端

如下爲補充或者本身薄弱的環節:(不少是網上搜的,回頭慢慢消化)java

1、Tipsnode

ctrl+shift+r : open resource, 打開資源.
它能夠打開當前eclipse的工做區中全部(打開的)工程中全部類型的文件,但只限手動編寫的文件,不含工程中引用到的
jar包中的類、接口;
ctrl+shift+t : open type, 打開類型.
它能夠打開當前eclipse的工做區中全部(打開的)工程中全部java文件,包括jar包中的類和接口.mysql

2、二分查找法nginx

二分查找又稱折半查找,優勢是比較次數少,查找速度快,平均性能好;其缺點是要求待查表爲有序表,且插入刪除困難。所以,折半查找方法適用於不常常變更而查找頻繁的有序列表。程序員

首先,假設表中元素是按升序排列,將表中間位置記錄的關鍵字與查找關鍵字比較,若是二者相等,則查找成功;不然利用中間位置記錄將表分紅前、後兩個子表,若是中間位置記錄的關鍵字大於查找關鍵字,則進一步查找前一子表,不然進一步查找後一子表。web

重複以上過程,直到找到知足條件的記錄,使查找成功,或直到子表不存在爲止,此時查找不成功。面試

 

二分查找的基本思想是將n個元素分紅大體相等的兩部分,取a[n/2]與x作比較,若是x=a[n/2],則找到x,算法停止;
若是x<a[n/2],則只要在數組a的左半部分繼續搜索x,若是x>a[n/2],則只要在數組a的右半部搜索x.
時間複雜度無非就是while循環的次數!
總共有n個元素,
漸漸跟下去就是n,n/2,n/4,....n/2^k(接下來操做元素的剩餘個數),其中k就是循環的次數
因爲你n/2^k取整後>=1
即令n/2^k=1
可得k=log2n,(是以2爲底,n的對數)
因此時間複雜度能夠表示O(h)=O(log2n)
下面提供一段二分查找實現的 僞代碼:
BinarySearch(max,min,des)
mid-<(max+min)/2
while(min<=max)
mid=(min+max)/2
if mid=des then
return mid
elseif mid >des then
max=mid-1
else
min=mid+1
return max
 

3、元數據ajax

元數據被定義爲:描述數據的數據,對數據及信息資源的描述性信息。

元數據(Metadata)是描述其它數據的數據(data about other data),或者說是用於提供某種資源的有關信息的結構數據(structured data)。
元數據是描述信息資源或數據等對象的數據,其使用目的在於:識別資源;評價資源;追蹤資源在使用過程當中的變化;實現簡單高效地管理大量網絡化數據;實現信息資源的有效發現、查找、一體化組織和對使用資源的有效管理。
 
元數據的 基本特色主要有:
a)元數據一經創建,即可共享。元數據的結構和完整性依賴於信息資源的價值和使用環境;元數據的開發與利用環境每每是一個變化的分佈式環境;任何一種格式都不可能徹底知足不一樣團體的不一樣須要;
b)元數據首先是一種編碼體系。元數據是用來描述數字化信息資源,特別是網絡信息資源的編碼體系,這致使了元數據和傳統數據編碼體系的根本區別;元數據的最爲重要的特徵和功能是爲數字化信息資源創建一種機器可理解框架。
元數據體系構建了電子政務的邏輯框架和基本模型,從而決定了電子政務的功能特徵、運行模式和系統運行的整體性能。電子政務的運做都基於元數據來實現。
其主要 做用有:描述功能、整合功能、控制功能和代理功能。
因爲元數據也是數據,所以能夠用相似數據的方法在數據庫中進行存儲和獲取。若是提供數據元的組織同時提供描述數據元的元數據,將會使數據元的使用變得準確而高效。用戶在使用數據時能夠首先查看其元數據以便可以獲取本身所需的信息。
 

4、this的用法

 

this關鍵字主要有三個應用
(1)this調用本類中的屬性,也就是類中的成員變量
(2)this調用本類中的其餘方法
(3)this調用本類中的其餘構造方法,調用時要放在構造方法的首行


Public Class Student {
String name; //定義一個成員變量name
private void SetName(String name) { //定義一個參數(局部變量)name
this.name=name; //將局部變量的值傳遞給成員變量
}
}

 

應用一:引用成員變量

如上面這段代碼中,有一個成員變量name,同時在方法中有一個形式參數,名字也是name,而後在方法中將形式參數name的值傳遞給成員變量name,雖然咱們能夠看明白這個代碼的含義,可是做爲Java編譯器它是怎麼判斷的呢?

究竟是將形式參數name的值傳遞給成員變量name,仍是反過來將成員變量name的值傳遞給形式參數name呢?也就是說,兩個變量名字若是相同的話,那麼Java如何判斷使用哪一個變量?此時this這個關鍵字就起到做用了。

this這個關鍵字其表明的就是對象中的成員變量或者方法。也就是說,若是在某個變量前面加上一個this關鍵字,其指的就是這個對象的成員變量或者方法,而不是指成員方法的形式參數或者局部變量。

爲此在上面這個代碼中,this.name表明的就是對象中的成員變量,又叫作對象的屬性,然後面的name則是方法的形式參數,代碼this.name=name就是將形式參數的值傳遞給成員變量。這就是上面這個代碼的具體含義。

通常狀況下,在Java語言中引用成員變量或者成員方法都是以對象名.成員變量或者對象名.成員方法的形式。不過有些程序員即便在沒有相同變量的時候,也喜歡使用this.成員變量的形式來引用變量,這主要是從便於代碼的閱讀考慮的。

一看到這個this關鍵字就知道如今引用的變量是成員變量或者成員方法,而不是局部變量。這無形中就提升了代碼的閱讀性。不過話說回來,這是this關鍵字在Java語言中的最簡單的應用。從這個應用中,咱們能夠看出this關鍵字其表明的就是對象的名字。

其實若是是局部變量的話,也是相同的道理。如在上面的代碼中,name不是形式參數,而是一個局部變量。此時Java也會遇到相同的疑惑,即變量名name表明的究竟是局部變量仍是形式參數?name=name到底表明的是什麼含義?根據局部變量的做用域,在方法內部,若是局部變量與成員變量同名的話,那麼是以局部變量爲準。但是在name=name這個賦值語句中,將局部變量的值賦值給本身,顯然並非很合適。

根據代碼的含義,原本的意思應該是將局部變量賦值給成員變量。爲了更清晰的表達這個含義,爲此最好採用以下的書寫格式this.name=name。這裏的this關鍵字含義就是對象名student,爲此this.name就表示student.name。

 

應用二:調用類的構造方法

public class Student { //定義一個類,類的名字爲student。
public Student() { //定義一個方法,名字與類相同故爲構造方法
this(「Hello!」);
}
public Student(String name) { //定義一個帶形式參數的構造方法
}
}


this關鍵字除了能夠調用成員變量以外,還能夠調用構造方法。在一個Java類中,其方法能夠分爲成員方法和構造方法兩種。

構造方法是一個與類同名的方法,在Java類中必須存在一個構造方法。若是在代碼中沒有顯示的體現構造方法的話,那麼編譯器在編譯的時候會自動添加一個沒有形式參數的構造方法。這個構造方法跟普通的成員方法仍是有不少不一樣的地方。如構造方法一概是沒有返回值的,並且也不用void關鍵字來講明這個構造方法沒有返回值。而普通的方法能夠有返回值、也能夠沒有返回值,程序員能夠根據本身的須要來定義。不過若是普通的方法沒有返回值的話,那麼必定要在方法定義的時候採用void關鍵字來進行說明。

其次構造方法的名字有嚴格的要求,即必須與類的名字相同。也就是說,Java編譯器發現有個方法與類的名字相同才把其看成構造方法來對待。而對於普通方法的話,則要求不可以與類的名字相同,並且多個成員方法不可以採用相同的名字。在一個類中能夠存在多個構造方法,這些構造方法都採用相同的名字,只是形式參數不一樣。Java語言就憑形式參數不一樣來判斷調用哪一個構造方法。

在上面這段代碼中,定義了兩個構造方法,一個帶參數,另外一個沒有帶參數。構造方法都不會有返回值,不過因爲構造方法的特殊性,爲此沒必要要在構造方法定義時帶上void關鍵字來講明這個問題。在第一個沒有帶參數的構造方法中,使用了this(「Hello!」)這句代碼,這句代碼表示什麼含義呢?

在構造方法中使this關鍵字表示調用類中的構造方法。若是一個類中有多個構造方法,由於其名字都相同,跟類名一致,那麼這個this究竟是調用哪一個構造方法呢?其實,這跟採用其餘方法引用構造方法同樣,都是經過形式參數來調用構造方法的。如上例中,this關鍵字後面加上了一個參數,那麼就表示其引用的是帶參數的構造方法。

若是如今有三個構造方法,分別爲不帶參數、帶一個參數、帶兩個參數。那麼Java編譯器會根據所傳遞的參數數量的不一樣,來判斷該調用哪一個構造方法。從上面示例中能夠看出,this關鍵字不只能夠用來引用成員變量,並且還能夠用來引用構造方法。

不過若是要使用這種方式來調用構造方法的話,有一個語法上的限制。通常來講,利用this關鍵字來調用構造方法,只有在無參數構造方法中第一句使用this調用有參數的構造方法。不然的話,翻譯的時候,就會有錯誤信息。這跟引用成員變量不一樣。若是引用成員變量的話,this關鍵字是沒有位置上的限制的。若是不熟悉這個限制的話,那麼仍是老老實實的採用傳統的構造方法調用方式爲好。雖然比較麻煩,可是至少不會出錯。


應用三:返回對象的值
this關鍵字除了能夠引用變量或者成員方法以外,還有一個重大的做用就是返回類的引用。如在代碼中,能夠使用return this,來返回某個類的引用。此時這個this關鍵字就表明類的名稱。如代碼在上面student類中,那麼代碼表明的含義就是return student。可見,這個this關鍵字除了能夠引用變量或者成員方法以外,還能夠做爲類的返回值,這纔是this關鍵字最引人注意的地方。

 

5、接口和抽象類區別(面試題)

abstract class和interface是Java語言中對於抽象類定義進行支持的兩種機制,正是因爲這兩種機制的存在,才賦予了Java強大的面向對象能力。 abstract class和interface之間在對於抽象類定義的支持方面具備很大的類似性,甚至能夠相互替換,所以不少開發者在進行抽象類定義時對於 abstract class和interface的選擇顯得比較隨意。

其實,二者之間仍是有很大的區別的,對於它們的選擇甚至反映出對於問題領域本質的理解、對於設計意圖的理解是否正確、合理。本文將對它們之間的區別進行一番剖析,試圖給開發者提供一個在兩者之間進行選擇的依據。

(一)理解抽象類

abstract class和interface在Java語言中都是用來進行抽象類(本文中的抽象類並不是從abstract class翻譯而來,它表示的是一個抽象體,而abstract class爲Java語言中用於定義抽象類的一種方法,請讀者注意區分)定義的,那麼什麼是抽象類,使用抽象類能爲咱們帶來什麼好處呢?

在面向對象的概念中,咱們知道全部的對象都是經過類來描繪的,可是反過來卻不是 這樣。並非全部的類都是用來描繪對象的,若是一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。抽象類每每用來表徵咱們在對問題領 域進行分析、設計中得出的抽象概念,是對一系列看上去不一樣,可是本質上相同的具體概念的抽象。

好比:若是咱們進行一個圖形編輯軟件的開發,就會發現問題領域存在着圓、三角形 這樣一些具體概念,它們是不一樣的,可是它們又都屬於形狀這樣一個概念,形狀這個概念在問題領域是不存在的,它就是一個抽象概念。正是由於抽象的概念在問題 領域沒有對應的具體概念,因此用以表徵抽象概念的抽象類是不可以實例化的。

在面向對象領域,抽象類主要用來進行類型隱藏。咱們能夠構造出一個固定的一組行 爲的抽象描述,可是這組行爲卻可以有任意個可能的具體實現方式。這個抽象描述就是抽象類,而這一組任意個可能的具體實現則表現爲全部可能的派生類。模塊可 以操做一個抽象體。因爲模塊依賴於一個固定的抽象體,所以它能夠是不容許修改的;同時,經過從這個抽象體派生,也可擴展此模塊的行爲功能。熟悉OCP的讀 者必定知道,爲了可以實現面向對象設計的一個最核心的原則OCP(Open-Closed Principle),抽象類是其中的關鍵所在。

 

(二)從語法定義層面看abstract class和interface

在語法層面,Java語言對於abstract class和interface給出了不一樣的定義方式,下面以定義一個名爲Demo的抽象類爲例來講明這種不一樣。使用abstract class的方式定義Demo抽象類的方式以下:

 

java 代碼
  1. abstract class Demo {    
  2.   
  3. abstract void method1();    
  4.   
  5. abstract void method2();    
  6.   
  7. …    
  8.   
  9. }    

 

 

使用interface的方式定義Demo抽象類的方式以下:

 

java 代碼
  1. interface Demo {    
  2.   
  3. void method1();    
  4.   
  5. void method2();    
  6.   
  7. …    
  8.   
  9. }    

 

 

在abstract class方式中,Demo能夠有本身的數據成員,也能夠有非abstarct的成員方法,而在interface方式的實現中,Demo只可以有靜態的 不能被修改的數據成員(也就是必須是static final的,不過在interface中通常不定義數據成員),全部的成員方法都是abstract的。從某種意義上說,interface是一種特殊 形式的abstract class。

從編程的角度來看,abstract class和interface均可以用來實現"design by contract"的思想。可是在具體的使用上面仍是有一些區別的。

首先,abstract class在Java語言中表示的是一種繼承關係,一個類只能使用一次繼承關係。可是,一個類卻能夠實現多個interface。也許,這是Java語言的設計者在考慮Java對於多重繼承的支持方面的一種折中考慮吧。

其次,在abstract class的定義中,咱們能夠賦予方法的默認行爲。可是在interface的定義中,方法卻不能擁有默認行爲,爲了繞過這個限制,必須使用委託,可是這會 增長一些複雜性,有時會形成很大的麻煩。

在抽象類中不能定義默認行爲還存在另外一個比較嚴重的問題,那就是可能會形成維護上的 麻煩。由於若是後來想修改類的界面(通常經過abstract class或者interface來表示)以適應新的狀況(好比,添加新的方法或者給已用的方法中添加新的參數)時,就會很是的麻煩,可能要花費不少的時 間(對於派生類不少的狀況,尤其如此)。可是若是界面是經過abstract class來實現的,那麼可能就只須要修改定義在abstract class中的默認行爲就能夠了。

一樣,若是不能在抽象類中定義默認行爲,就會致使一樣的方法實現出如今該抽象類 的每個派生類中,違反了"one rule,one place"原則,形成代碼重複,一樣不利於之後的維護。所以,在abstract class和interface間進行選擇時要很是的當心。

 

(三)從設計理念層面看abstract class和interface

上面主要從語法定義和編程的角度論述了abstract class和interface的區別,這些層面的區別是比較低層次的、非本質的。本文將從另外一個層面:abstract class和interface所反映出的設計理念,來分析一下兩者的區別。做者認爲,從這個層面進行分析才能理解兩者概念的本質所在。

前面已經提到過,abstarct class在Java語言中體現了一種繼承關係,要想使得繼承關係合理,父類和派生類之間必須存在"is a"關係,即父類和派生類在概念本質上應該是相同的。對於interface 來講則否則,並不要求interface的實現者和interface定義在概念本質上是一致的,僅僅是實現了interface定義的契約而已。爲了使 論述便於理解,下面將經過一個簡單的實例進行說明。

考慮這樣一個例子,假設在咱們的問題領域中有一個關於Door的抽象概念,該Door具備執行兩個動做open和close,此時咱們能夠經過abstract class或者interface來定義一個表示該抽象概念的類型,定義方式分別以下所示:

 

使用abstract class方式定義Door:

 

java 代碼

 

  1. abstract class Door {    
  2.   
  3. abstract void open();    
  4.   
  5. abstract void close();    
  6.   
  7. }    

使用interface方式定義Door:

 

java 代碼
  1. interface Door {    
  2.   
  3. void open();    
  4.   
  5. void close();    
  6.   
  7. }    

 

 

其餘具體的Door類型能夠extends使用abstract class方式定義的Door或者implements使用interface方式定義的Door。看起來好像使用abstract class和interface沒有大的區別。

若是如今要求Door還要具備報警的功能。咱們該如何設計針對該例子的類結構呢(在 本例中,主要是爲了展現abstract class和interface反映在設計理念上的區別,其餘方面無關的問題都作了簡化或者忽略)下面將羅列出可能的解決方案,並從設計理念層面對這些不 同的方案進行分析。

解決方案一:

簡單的在Door的定義中增長一個alarm方法,以下:

 

java 代碼

 

 

或者

 

java 代碼
  1. interface Door {    
  2.   
  3. void open();    
  4.   
  5. void close();    
  6.   
  7. void alarm();    
  8.   
  9. }    

 

 

那麼具備報警功能的AlarmDoor的定義方式以下:

 

java 代碼
  1. class AlarmDoor extends Door {    
  2.   
  3. void open() { … }    
  4.   
  5. void close() { … }    
  6.   
  7. void alarm() { … }    
  8.   
  9. }    

 

 

或者

 

java 代碼
  1. class AlarmDoor implements Door {    
  2.   
  3. void open() { … }    
  4.   
  5. void close() { … }    
  6.   
  7. void alarm() { … }    
  8.   
  9. }    

 

 

這種方法違反了面向對象設計中的一個核心原則ISP(Interface Segregation Priciple),在Door的定義中把Door概念自己固有的行爲方法和另一個概念"報警器"的行爲方法混在了一塊兒。這樣引發的一個問題是那些僅僅 依賴於Door這個概念的模塊會由於"報警器"這個概念的改變(好比:修改alarm方法的參數)而改變,反之依然。

解決方案二:

既然open、close和alarm屬於兩個不一樣的概念,根據ISP原則應該把它 們分別定義在表明這兩個概念的抽象類中。定義方式有:這兩個概念都使用abstract class方式定義;兩個概念都使用interface方式定義;一個概念使用abstract class方式定義,另外一個概念使用interface方式定義。

顯然,因爲Java語言不支持多重繼承,因此兩個概念都使用abstract class方式定義是不可行的。後面兩種方式都是可行的,可是對於它們的選擇卻反映出對於問題領域中的概念本質的理解、對於設計意圖的反映是否正確、合理。咱們一一來分析、說明。

若是兩個概念都使用interface方式來定義,那麼就反映出兩個問題:

一、咱們可能沒有理解清楚問題領域,AlarmDoor在概念本質上究竟是Door仍是報警器?

二、若是咱們對於問題領域的理解沒有問題,好比:咱們經過對於問題領域的分析發現 AlarmDoor在概念本質上和Door是一致的,那麼咱們在實現時就沒有可以正確的揭示咱們的設計意圖,由於在這兩個概念的定義上(均使用 interface方式定義)反映不出上述含義。

若是咱們對於問題領域的理解是:AlarmDoor在概念本質上是Door,同 時它有具備報警的功能。咱們該如何來設計、實現來明確的反映出咱們的意思呢?前面已經說過,abstract class在Java語言中表示一種繼承關係,而繼承關係在本質上是"is a"關係。因此對於Door這個概念,咱們應該使用abstarct class方式來定義。另外,AlarmDoor又具備報警功能,說明它又可以完成報警概念中定義的行爲,因此報警概念能夠經過interface方式定 義。以下所示:

 

java 代碼
  1. abstract class Door {    
  2.   
  3. abstract void open();    
  4.   
  5. abstract void close();    
  6.   
  7. }    

 

java 代碼
  1. interface Alarm {    
  2.   
  3. void alarm();    
  4.   
  5. }    

 

java 代碼
  1. class AlarmDoor extends Door implements Alarm {    
  2.   
  3. void open() { … }    
  4.   
  5. void close() { … }    
  6.   
  7. void alarm() { … }    
  8.   
  9. }    

 

 

這種實現方式基本上可以明確的反映出咱們對於問題領域的理解,正確的揭示咱們的設計 意圖。其實abstract class表示的是"is a"關係,interface表示的是"like a"關係,你們在選擇時能夠做爲一個依據,固然這是創建在對問題領域的理解上的,好比:若是咱們認爲AlarmDoor在概念本質上是報警器,同時又具備 Door的功能,那麼上述的定義方式就要反過來了。

abstract class和interface是Java語言中的兩種定義抽象類的方式,它們之間有很大的類似性。可是對於它們的選擇卻又每每反映出對於問題領域中的概 念本質的理解、對於設計意圖的反映是否正確、合理,由於它們表現了概念間的不一樣的關係(雖然都可以實現需求的功能)。這其實也是語言的一種的慣用法。

 

 (四)總結幾句話來講:

一、抽象類和接口都不能直接實例化,若是要實例化,抽象類變量必須指向實現全部抽象方法的子類對象,接口變量必須指向實現全部接口方法的類對象。

二、抽象類要被子類繼承,接口要被類實現。

三、接口只能作方法申明,抽象類中能夠作方法申明,也能夠作方法實現

四、接口裏定義的變量只能是公共的靜態的常量,抽象類中的變量是普通變量。

五、抽象類裏的抽象方法必須所有被子類所實現,若是子類不能所有實現父類抽象方法,那麼該子類只能是抽象類。一樣,一個實現接口的時候,如不能所有實現接口方法,那麼該類也只能爲抽象類。

六、抽象方法只能申明,不能實現。abstract void abc();不能寫成abstract void abc(){}。

七、抽象類裏能夠沒有抽象方法

八、若是一個類裏有抽象方法,那麼這個類只能是抽象類

九、抽象方法

 

6、自定義異常類

轉載自:http://blog.csdn.net/csdn_gia/article/details/53032248

 sun提供了不少的異常類給咱們用於描述程序中各類的不正常狀況,可是sun 給我
提供異常類還不足以描述咱們現實生活中全部不正常狀況,那麼這時候咱們就須要
自定義異常類。

需求: 模擬feiQ上線的時候,若是沒有插上網線,那麼就拋出一個沒有插上網線的異常,
若是已經插上了網上,那麼就正常顯示好友列表。

自定義異常類的步驟:  自定義一個類繼承Exception便可。

 

[java]  view plain  copy
 
  1. //自定義了一個沒有網線的異常類了。  
  2. class NoIpException extends Exception{  
  3.   
  4.   
  5.     public NoIpException(String message){  
  6.         super(message);  //調用了Exception一個參數的構造函數。  
  7.     }  
  8.   
  9. }  
  10.   
  11.   
  12.   
  13. class Demo2   
  14. {  
  15.     public static void main(String[] args)   
  16.     {  
  17.         String ip = "192.168.10.100";  
  18.         ip = null;  
  19.         try{  
  20.             feiQ(ip);  // 若是調用了一個聲明拋出異常類型的方法,那麼調用者必需要處理。  
  21.           
  22.           
  23.         }catch(NoIpException e){  
  24.             e.printStackTrace();  
  25.             System.out.println("立刻插上網線!");  
  26.         }  
  27.           
  28.   
  29.     }  
  30.   
  31.   
  32.     public static void feiQ(String ip) throws NoIpException{  
  33.         if(ip==null){  
  34.             throw new  NoIpException("沒有插網線啊,小白!");  
  35.         }  
  36.         System.out.println("正常顯示好友列表..");  
  37.     }  
  38.   
  39.   
  40. }  


需求:模擬你去吃木桶飯,若是帶錢少於了10塊,那麼就拋出一個沒有帶夠錢的異常對象,
若是帶夠了,那麼就能夠吃上香噴噴的地溝油木桶飯.

 

 

[java]  view plain  copy
 
    1. //定義沒錢的異常  
    2. class NoMoneyException extends Exception {  
    3.   
    4.     public NoMoneyException(String message){  
    5.         super(message);  
    6.     }  
    7.   
    8. }  
    9.   
    10.   
    11.   
    12. class Demo3   
    13. {  
    14.     public static void main(String[] args)   
    15.     {  
    16.         //System.out.println("Hello World!");  
    17.         try{  
    18.             eat(9);  
    19.   
    20.         }catch(NoMoneyException e){  
    21.             e.printStackTrace();  
    22.             System.out.println("跟我洗碗一個月!!");  
    23.         }  
    24.     }  
    25.   
    26.   
    27.     public static void eat(int money) throws NoMoneyException{  
    28.         if(money<10){  
    29.             throw new NoMoneyException("吃霸王餐");  
    30.         }  
    31.         System.out.println("吃上了香噴噴的地溝油木桶飯!!");  
    32.     }  
    33. }  

 

 

 

7、Entry

轉載自:http://www.cnblogs.com/guanjie20/p/3769772.html

Map是java中的接口,Map.Entry是Map的一個內部接口。

Map提供了一些經常使用方法,如keySet()、entrySet()等方法。

keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一個Set集合,此集合的類型爲Map.Entry。

Map.Entry是Map聲明的一個內部接口,此接口爲泛型,定義爲Entry<K,V>。它表示Map中的一個實體(一個key-value對)。接口中有getKey(),getValue方法。

         

        由以上能夠得出,遍歷Map的經常使用方法:

       1.  Map map = new HashMap();

           Irerator iterator = map.entrySet().iterator();

           while(iterator.hasNext()) {

                   Map.Entry entry = iterator.next();

                   Object key = entry.getKey();

                   //

           }

       2.Map map = new HashMap(); 

           Set  keySet= map.keySet();

           Irerator iterator = keySet.iterator;

           while(iterator.hasNext()) {

                   Object key = iterator.next();

                   Object value = map.get(key);

                   //

           }

 

       另外,還有一種遍歷方法是,單純的遍歷value值,Map有一個values方法,返回的是value的Collection集合。經過遍歷collection也能夠遍歷value,如

      Map map = new HashMap();

      Collection c = map.values();

      Iterator iterator = c.iterator();

      while(iterator.hasNext()) {

             Object value = iterator.next(); 

     }

 

 

8、GC工做機制詳解

轉載自:http://blog.csdn.net/tonytfjing/article/details/44278233

 

題外話:最近在應聘阿里2015暑期實習,感觸頗多。機會老是留給有準備的人的,因此日常必定要注意知識的鞏固和積累。知識的深度也要有必定的理解,不比別人知道的多,公司幹嗎選你?關於JVM和GC,我相信學Java的絕大部分人都聽過,不少公司的面試官都愛問,一開始我也很頭痛,問這麼底層幹什麼,因此我每次面試也只是看看答案敷衍了事。最近面完阿里感受真不能這樣,知識不只要知其然,還要知其因此然。其實弄懂了JVM和GC,對咱們理解不少java知識都有幫助。網上有不少關於GC和JVM的文章,這篇博文主要是根據我最近看《深刻理解Java虛擬機》的一些體會總結出來的,但願對新手有些幫助,也歡迎大牛拍磚。文章主要分爲如下四個部分

JVM結構、內存分配、垃圾回收算法、垃圾收集器。下面咱們一一來看。

1、JVM結構

根據《java虛擬機規範》規定,JVM的基本結構通常以下圖所示:

從左圖可知,JVM主要包括四個部分:

1.類加載器(ClassLoader):在JVM啓動時或者在類運行時將須要的class加載到JVM中。(右圖表示了從java源文件到JVM的整個過程,可配合理解。 關於類的加載機制,能夠參考http://blog.csdn.net/tonytfjing/article/details/47212291

2.執行引擎:負責執行class文件中包含的字節碼指令(執行引擎的工做機制,這裏也不細說了,這裏主要介紹JVM結構);

3.內存區(也叫運行時數據區):是在JVM運行的時候操做所分配的內存區。運行時內存區主要能夠劃分爲5個區域,如圖:

  • 方法區(Method Area):用於存儲類結構信息的地方,包括常量池、靜態變量、構造函數等。雖然JVM規範把方法區描述爲堆的一個邏輯部分, 但它卻有個別名non-heap(非堆),因此你們不要搞混淆了。方法區還包含一個運行時常量池。
  • java堆(Heap):存儲java實例或者對象的地方。這塊是GC的主要區域(後面解釋)。從存儲的內容咱們能夠很容易知道,方法區和堆是被全部java線程共享的。
  • java棧(Stack):java棧老是和線程關聯在一塊兒,每當建立一個線程時,JVM就會爲這個線程建立一個對應的java棧。在這個java棧中又會包含多個棧幀,每運行一個方法就建立一個棧幀,用於存儲局部變量表、操做棧、方法返回值等。每個方法從調用直至執行完成的過程,就對應一個棧幀在java棧中入棧到出棧的過程。因此java棧是現成私有的。
  • 程序計數器(PC Register):用於保存當前線程執行的內存地址。因爲JVM程序是多線程執行的(線程輪流切換),因此爲了保證線程切換回來後,還能恢復到原先狀態,就須要一個獨立的計數器,記錄以前中斷的地方,可見程序計數器也是線程私有的。
  • 本地方法棧(Native Method Stack):和java棧的做用差很少,只不過是爲JVM使用到的native方法服務的。

4.本地方法接口:主要是調用C或C++實現的本地方法及返回結果。

2、內存分配

我以爲了解垃圾回收以前,得先了解JVM是怎麼分配內存的,而後識別哪些內存是垃圾須要回收,最後纔是用什麼方式回收。

Java的內存分配原理與C/C++不一樣,C/C++每次申請內存時都要malloc進行系統調用,而系統調用發生在內核空間,每次都要中斷進行切換,這須要必定的開銷,而Java虛擬機是先一次性分配一塊較大的空間,而後每次new時都在該空間上進行分配和釋放,減小了系統調用的次數,節省了必定的開銷,這有點相似於內存池的概念;二是有了這塊空間事後,如何進行分配和回收就跟GC機制有關了。

java通常內存申請有兩種:靜態內存和動態內存。很容易理解,編譯時就可以肯定的內存就是靜態內存,即內存是固定的,系統一次性分配,好比int類型變量;動態內存分配就是在程序執行時才知道要分配的存儲空間大小,好比java對象的內存空間。根據上面咱們知道,java棧、程序計數器、本地方法棧都是線程私有的,線程生就生,線程滅就滅,棧中的棧幀隨着方法的結束也會撤銷,內存天然就跟着回收了。因此這幾個區域的內存分配與回收是肯定的,咱們不須要管的。可是java堆和方法區則不同,咱們只有在程序運行期間才知道會建立哪些對象,因此這部份內存的分配和回收都是動態的。通常咱們所說的垃圾回收也是針對的這一部分。

總之Stack的內存管理是順序分配的,並且定長,不存在內存回收問題;而Heap 則是爲java對象的實例隨機分配內存,不定長度,因此存在內存分配和回收的問題;

3、垃圾檢測、回收算法

垃圾收集器通常必須完成兩件事:檢測出垃圾;回收垃圾。怎麼檢測出垃圾?通常有如下幾種方法:

引用計數法:給一個對象添加引用計數器,每當有個地方引用它,計數器就加1;引用失效就減1。

好了,問題來了,若是我有兩個對象A和B,互相引用,除此以外,沒有其餘任何對象引用它們,實際上這兩個對象已經沒法訪問,便是咱們說的垃圾對象。可是互相引用,計數不爲0,致使沒法回收,因此還有另外一種方法:

可達性分析算法:以根集對象爲起始點進行搜索,若是有對象不可達的話,便是垃圾對象。這裏的根集通常包括java棧中引用的對象、方法區常良池中引用的對象

本地方法中引用的對象等。

總之,JVM在作垃圾回收的時候,會檢查堆中的全部對象是否會被這些根集對象引用,不可以被引用的對象就會被垃圾收集器回收。通常回收算法也有以下幾種:

1.標記-清除(Mark-sweep)

算法和名字同樣,分爲兩個階段:標記和清除。標記全部須要回收的對象,而後統一回收。這是最基礎的算法,後續的收集算法都是基於這個算法擴展的。

不足:效率低;標記清除以後會產生大量碎片。效果圖以下:

2.複製(Copying)

此算法把內存空間劃爲兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象複製到另一個區域中。此算法每次只處理正在使用中的對象,所以複製成本比較小,同時複製過去之後還能進行相應的內存整理,不會出現「碎片」問題。固然,此算法的缺點也是很明顯的,就是須要兩倍內存空間。效果圖以下:

3.標記-整理(Mark-Compact)

此算法結合了「標記-清除」和「複製」兩個算法的優勢。也是分兩階段,第一階段從根節點開始標記全部被引用對象,第二階段遍歷整個堆,把清除未標記對象而且把存活對象「壓縮」到堆的其中一塊,按順序排放。此算法避免了「標記-清除」的碎片問題,同時也避免了「複製」算法的空間問題。效果圖以下:

(1,2,3 圖文摘自 http://pengjiaheng.iteye.com/blog/520228,感謝原做者。)

4.分代收集算法

這是當前商業虛擬機經常使用的垃圾收集算法。分代的垃圾回收策略,是基於這樣一個事實:不一樣的對象的生命週期是不同的。所以,不一樣生命週期的對象能夠採起不一樣的收集方式,以便提升回收效率。

爲何要運用分代垃圾回收策略?在java程序運行的過程當中,會產生大量的對象,因每一個對象所能承擔的職責不一樣所具備的功能不一樣因此也有着不同的生命週期,有的對象生命週期較長,好比Http請求中的Session對象,線程,Socket鏈接等;有的對象生命週期較短,好比String對象,因爲其不變類的特性,有的在使用一次後便可回收。試想,在不進行對象存活時間區分的狀況下,每次垃圾回收都是對整個堆空間進行回收,那麼消耗的時間相對會很長,並且對於存活時間較長的對象進行的掃描工做等都是徒勞。所以就須要引入分治的思想,所謂分治的思想就是因地制宜,將對象進行代的劃分,把不一樣生命週期的對象放在不一樣的代上使用不一樣的垃圾回收方式。

如何劃分?將對象按其生命週期的不一樣劃分紅:年輕代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)。其中持久代主要存放的是類信息,因此與java對象的回收關係不大,與回收息息相關的是年輕代和年老代。這裏有個比喻很形象

「假設你是一個普通的 Java 對象,你出生在 Eden 區,在 Eden 區有許多和你差很少的小兄弟、小姐妹,能夠把 Eden 區當成幼兒園,在這個幼兒園裏你們玩了很長時間。Eden 區不能無休止地放大家在裏面,因此當年紀稍大,你就要被送到學校去上學,這裏假設從小學到高中都稱爲 Survivor 區。開始的時候你在 Survivor 區裏面劃分出來的的「From」區,讀到高年級了,就進了 Survivor 區的「To」區,中間因爲學習成績不穩定,還常常來回折騰。直到你 18 歲的時候,高中畢業了,該去社會上闖闖了。因而你就去了年老代,年老代裏面人也不少。在年老代裏,你生活了 20 年 (每次 GC 加一歲),最後壽終正寢,被 GC 回收。有一點沒有提,你在年老代遇到了一個同窗,他的名字叫愛德華 (慕光之城裏的帥哥吸血鬼),他以及他的家族永遠不會死,那麼他們就生活在永生代。」

 

具體區域能夠經過VisualVM中的VisaulGC插件查看,如圖(openjdk 1.7):

年輕代:是全部新對象產生的地方。年輕代被分爲3個部分——Enden區和兩個Survivor區(From和to)當Eden區被對象填滿時,就會執行Minor GC。並把全部存活下來的對象轉移到其中一個survivor區(假設爲from區)。Minor GC一樣會檢查存活下來的對象,並把它們轉移到另外一個survivor區(假設爲to區)。這樣在一段時間內,總會有一個空的survivor區。通過屢次GC週期後,仍然存活下來的對象會被轉移到年老代內存空間。一般這是在年輕代有資格提高到年老代前經過設定年齡閾值來完成的。須要注意,Survivor的兩個區是對稱的,沒前後關係,from和to是相對的。

年老代:在年輕代中經歷了N次回收後仍然沒有被清除的對象,就會被放到年老代中,能夠說他們都是久經沙場而不亡的一代,都是生命週期較長的對象。對於年老代和永久代,就不能再採用像年輕代中那樣搬移騰挪的回收算法,由於那些對於這些回收戰場上的老兵來講是小兒科。一般會在老年代內存被佔滿時將會觸發Full GC,回收整個堆內存。

持久代:用於存放靜態文件,好比java類、方法等。持久代對垃圾回收沒有顯著的影響。 

分代回收的效果圖以下:

我這裏之因此最後講分代,是由於分代裏涉及了前面幾種算法。年輕代:涉及了複製算法;年老代:涉及了「標記-整理(Mark-Sweep)」的算法。

4、垃圾收集器

垃圾收集算法是內存回收的方法論,而實現這些方法論的則是垃圾收集器。不一樣廠商不一樣版本JVM所提供的垃圾收集器可能不一樣,這裏參照《深刻理解Java虛擬機》說的是JDK1.7版本Hotspot虛擬機,關於垃圾收集器有篇博文總結的不錯,我就不說了,詳見:http://blog.csdn.net/java2000_wl/article/details/8030172

總結

雖然我不認爲學習java必須去了解Java底層的實現,可是我想若是你更加理解JVM和GC的話,你就會更加理解Java,在之後的學習和工做中絕對受益不淺。畢竟咱們的目標不是刷牆工,不是搬運工,而是開發攻城獅啊!

 

 

9、高併發(找到兩篇文章先存下來,沒太懂的說,感受本身功力差不少)

轉載1:http://www.oschina.net/news/73476/programmer-high-concurrency

簡單理解下高併發:

高併發是指在同一個時間點,有不少用戶同時的訪問URL地址,好比:淘寶的雙11,雙12,就會產生高併發,如貼吧的爆吧,就是惡意的高併發請 求,也就是DDOS攻擊,再屌絲點的說法就像玩擼啊擼被ADC暴擊了同樣,那傷害你懂得(若是你看懂了,這個說法說明是正在奔向人生巔峯的屌絲。

高併發會來帶的後果

  • 服務端:

    • 致使站點服務器/DB服務器資源被佔滿崩潰,數據的存儲和更新結果和理想的設計是不同的,好比:出現重複的數據記錄,屢次添加了用戶積分等。

  • 用戶角度:

    • 尼瑪,這麼卡,老子來參加活動的,刷新了仍是這樣,垃圾網站,不再來了。

  • 個人經歷:
    在作公司產品網站的過程當中,常常會有這樣的需求,好比什麼搞個活動專題,抽獎,簽到,搞個積分競拍等等,若是沒有考慮到高併發下的數據處理,那就Game Over了,很容易致使抽獎被多抽走,簽到會發現一個用戶有多條記錄,簽到一次得到了得到了多積分,等等,各類超出正常邏輯的現象,這就是作產品網站必須 考慮的問題,由於這些都是面向大量用戶的,而不是像作ERP管理系統,OA系統那樣,只是面向員工。

下面我進行實例分析,簡單粗暴,動態分析,純屬本人我的經驗分享,若有說錯,或者有更好的建議或者意見的請留言,你們一塊兒成長。

併發下的數據處理:

經過表設計,如:記錄表添加惟一約束,數據處理邏輯使用事物防止併發下的數據錯亂問題
經過服務端鎖進程防止包併發下的數據錯亂問題

這裏主要講述的是在併發請求下的數據邏輯處理的接口,如何保證數據的一致性和完整性,這裏的併發多是大量用戶發起的,也可能攻擊者經過併發工具發起的併發請求


如例子:經過表設計防止併發致使數據錯亂

  • 需求點 
    【簽到功能】 一天一個用戶只能簽到一次,
    簽到成功後用戶獲取到一個積分

  • 已知表 
    用戶表,包含積分字段   
    高併發意淫分析(屬於開發前的猜想): 
    在高併發的狀況下,會致使,一個用戶簽到記錄會有多條,或者用戶簽到後不止加一積分。

  • 個人設計 
    首先根據需求我會添加一張簽到記錄表,重點來了,這張表須要把用戶惟一標識字段(ID,Token)和簽到日期字段添加爲惟一約束,或者惟一索引,這樣就 能夠防止併發的時候插入重複用戶的簽到記錄。而後再程序代碼邏輯裏,先執行簽到數據的添加(這裏能夠防止併發,添加成功後再進行積分的添加,這樣就能夠防 止重複的添加積分了。最後我仍是建議全部的數據操做都寫在一個sql事務裏面,  這樣在添加失敗,或者編輯用戶積分失敗的時候能夠回滾數據。


如例子2(事務+經過更新鎖 防止併發致使數據錯亂 或者事物+Update的鎖表機制)

  • 需求點: 
    【抽獎功能】 抽獎一次消耗一個積分 抽獎中獎後編輯剩餘獎品總數 剩餘獎品總數爲0,或者用戶積分爲0的時候沒法進行抽獎

  • 已知表:  
    用戶表,包含積分字段 獎品表,包含獎品剩餘數量字段

  • 高併發意淫分析(屬於開發前的猜想): 
    在高併發的狀況下,會致使用戶參與抽獎的時候積分被扣除,而獎品實際上已經被抽完了

  • 個人設計: 
    在事物裏,經過WITH (UPDLOCK) 鎖住商品表,或者Update 表的獎品剩餘數量和最後編輯時間字段,來把數據行鎖住,而後進行用戶積分的消耗,都完成後提交事物,失敗就回滾。 這樣就能夠保證,只有可能存在一個操做在操做這件商品的數量,只有等到這個操做事物提交後,其餘的操做這個商品行的事物纔會繼續執行。


如例子3(經過程序代碼防止包併發下的數據錯亂問題)

  • 需求點:
    【緩存數據到cache裏】, 當緩存不存在的時候,從數據庫中獲取並保存在cache裏,若是存在從cache裏獲取,天天10點必須更新一次,其餘時間點緩存兩個小時更新一次 到10點的時候,凡是打開頁面的用戶會自動刷新頁面

  • 問題點:
    這裏有個邏輯用戶觸發緩存的更新,用戶刷新頁面,當緩存存在的時候,會取到最後一次緩存更新時間,若是當前時間大於十點,而且最後緩存時間是10點前,則 會從數據庫中從新獲取數據保存到cache中。 還有客戶端頁面會在10點時候用js發起頁面的刷新,就是由於有這樣的邏輯,致使10點的時候有不少併發請求同時過來,而後就會致使不少的sql查詢操 做,理想的邏輯是,只有一個請求會去數據庫獲取,其餘都是從緩存中獲取數據。(由於這個sql查詢很耗服務器性能,因此致使在10點的時候,忽然間數據庫 服務器壓力暴增)

  • 解決問題:
    C#經過 (鎖)lock,在從數據讀取到緩存的那段代碼前面加上鎖,這樣在併發的狀況下只會有一個請求是從數據庫裏獲取數據,其餘都是從緩存中獲取。


訪問量大的數據統計接口

  • 需求: 用戶行爲數據統計接口,用來記錄商品展現次數,用戶經過點擊圖片,或者連接,或者其餘方式進入到商品詳情的行爲次數

  • 問題點:
    這接口是給前端ajax使用,訪問量會很大,一頁面展現的時候就會有幾十件商品的展現,滾動條滾到到頁面顯示商品的時候就會請求接口進行展現數據的統計,每次翻頁又會加載幾十件

  • 意淫分析:
    設想若是同時有1W個用戶同時在線訪問頁面,一個次拉動滾動條屏幕頁面展現10件商品,這樣就會有10W個請求過來,服務端須要把請求數據入庫。在實際線上環境可能還會超過這個請求量,若是不通過進行高併發設計處理,服務器分分鐘給跪了。

  • 解決問題:
    咱們經過nodejs寫了一個數據處理接口,把統計數據先存到redis的list裏。(使用nodejs寫接口的好處是,nodejs使用單線程異步事件機制,高併發處理能力強,不會由於數據邏輯處理問題致使服務器資源被佔用而致使服務器宕機) 而後再使用nodejs寫了一個腳本,腳本功能就是從redis裏出列數據保存到mysql數據庫中。這個腳本會一直運行,當redis沒有數據須要同步到數據庫中的時候,sleep,讓在進行數據同步操做


高併發的下的服務器壓力均衡,合理站點架設,DB部署

如下我所知道的:

  1. 服務器代理nginx,作服務器的均衡負載,把壓力均衡到多臺服務器

  2. 部署集羣 mysql數據庫, redis服務器,或者mongodb服務器,把一些經常使用的查詢數據,而且不會常常的變化的數據保存到其餘nosql    DB服務器中,來減小數據庫服務器的壓力,加快數據的響應速度。

  3. 數據緩存,Cache

  4. 在高併發接口的設計中能夠使用具備高併發能力的編程語言去開發,如:nodejs 作web接口

  5. 服務器部署,圖片服務器分離,靜態文件走CDN

  6. DBA數據庫的優化查詢條件,索引優化

  7. 消息存儲機制,將數據添加到信息隊列中(redis list),而後再寫工具去入庫

  8. 腳本合理控制請求,如,防止用戶重複點擊致使的ajax多餘的請求,等等。

併發測試神器推薦

  1. Apache JMeter

  2. Microsoft Web Application Stress Tool

  3. Visual Studio 性能負載

文章來源:SFLYQ

 

 

 轉載2:http://www.cnblogs.com/lezai/p/4932396.html

以前我將高併發的解決方法誤認爲是線程或者是隊列能夠解決,由於高併發的時候是有不少用戶在訪問,致使出現系統數據不正確、丟失數據現象,因此想到 的是用隊列解決,其實隊列解決的方式也能夠處理,好比咱們在競拍商品、轉發評論微博或者是秒殺商品等,同一時間訪問量特別大,隊列在此起到特別的做用,將 全部請求放入隊列,以毫秒計時單位,有序的進行,從而不會出現數據丟失系統數據不正確的狀況。

 

今天我通過查資料,高併發的解決方法有倆種,一種是使用緩存、另外一種是使用生成靜態頁面;還有就是從最基礎的地方優化咱們寫代碼減小沒必要要的資源浪費:(

1.不要頻繁的new對象,對於在整個應用中只須要存在一個實例的類使用單例模式.對於String的鏈接操做,使用StringBuffer或者StringBuilder.對於utility類型的類經過靜態方法來訪問。

2. 避免使用錯誤的方式,如Exception能夠控制方法推出,可是Exception要保留stacktrace消耗性能,除非必要不要使用 instanceof作條件判斷,儘可能使用比的條件判斷方式.使用JAVA中效率高的類,好比ArrayList比Vector性能好。)

首先緩存技術我一直沒有使用過,我以爲應該是在用戶請求時將數據保存在緩存中,下次請求時會檢測緩存中是否有數據存在,防止屢次請求服務器,致使服務器性能下降,嚴重致使服務器崩潰,這只是我本身的理解,詳細的資料仍是須要在網上收集;

使用生成靜態頁面我想你們應該不模式,咱們見過不少網站當在請求的時候頁面的後最已經變了,如「http://developer.51cto.com/art/201207/348766.htm」該頁面實際上是一個服務器請求地址,在轉換成htm後,訪問速度將提高,由於靜態頁面不帶有服務器組件;在這裏我就多多介紹一下:

(一)什麼是頁面靜態化:

簡 單的說,咱們若是訪問一個連接 ,服務器對應的模塊會處理這個請求,轉到對應的jsp界面,最後生成咱們想要看到的數據。這其中的缺點是顯而易見的:由於每次請求服務器都會進行處理,如 果有太多的高併發請求,那麼就會加劇應用服務器的壓力,弄很差就把服務器 搞down 掉了。那麼如何去避免呢?若是咱們把對 test.do 請求後的結果保存成一個 html 文件,而後每次用戶都去訪問 ,這樣應用服務器的壓力不就減小了?

那麼靜態頁面從哪裏來呢?總不能讓咱們每一個頁面都手動處理吧?這裏就牽涉到咱們要講解的內容了,靜態頁面生成方案… 咱們須要的是自動的生成靜態頁面,當用戶訪問 ,會自動生成 test.html ,而後顯示給用戶。

(二)下面咱們在簡單介紹一下要想掌握頁面靜態化方案應該掌握的知識點:

一、 基礎- URL Rewrite

什麼是 URL Rewrite 呢 ? URL 重寫。用一個簡單的例子來講明問題:輸入網址 ,可是實際上訪問的倒是 abc.com/test.action,那咱們就能夠說 URL 被重寫了。這項技術應用普遍,有許多開源的工具能夠實現這個功能。

二、 基礎- Servlet web.xml

若是你還不知道 web.xml 中一個請求和一個 servlet 是如何匹配到一塊兒的,那麼請搜索一下 servlet 的文檔。這可不是亂說呀,有不少人就認爲 /xyz/*.do 這樣的匹配方式能有效。

若是你還不知道怎麼編寫一個 servlet ,那麼請搜索一下如何編寫 servlet.這可不是說笑呀,在各類集成工具漫天飛舞的今天,不少人都不會去從零編寫一個 servlet了。

(三)基本的方案介紹

 
其中,對於 URL Rewriter的部分,能夠使用收費或者開源的工具來實現,若是 url不是特別的複雜,能夠考慮在 servlet 中實現,那麼就是下面這個樣子:

 

 
 
總 結:其實咱們在開發中都不多考慮這種問題,直接都是先將功能實現,當一個程序員在幹到1到2年,就會感受光實現功能不是最主要的,安全性能、質量等等纔是 一個開發人員最該關心的。今天我所說的是高併發,個人解決思路是,一、採用分佈式應用設計二、分佈式緩存數據庫三、代碼優化

 

 

 

10、工廠模式

 老師代碼:

簡單工廠模式實現加減乘除法

 

1.建立運算的接口

public interface Operation {
    //提供計算兩個數字的方法
    double getResult(double num1,double num2);

}

2.建立對應的加減乘除四個實現類

複製代碼
public class Addition implements Operation { //加法

    @Override
    public double getResult(double num1, double num2) {
        return num1+num2;
    }

}
複製代碼
複製代碼
public class Minus implements Operation { //減法

    @Override
    public double getResult(double num1, double num2) {
        return num1-num2;
    }

}
複製代碼
複製代碼
public class Multiplication implements Operation {//乘法

    @Override
    public double getResult(double num1, double num2) {
        return num1*num2;
    }

}
複製代碼
複製代碼
public class Division implements Operation {//除法

    @Override
    public double getResult(double num1, double num2) {
        return num1/num2;
    }
}
複製代碼

3.建立工廠類

複製代碼
public class OperationFactory {  //計算機的工廠類
    /*
     * 工廠模式 是咱們最經常使用的實例化對象的模式!
     * 用工廠的方法替代new!
     * 雖然代碼量沒有減小  可是 提升了程序的擴展性!
     */
    public static  Operation  getOperation(String o){
        Operation operation=null; //多態
        switch (o) {
        case "+":
            operation=new Addition();
            break;
        case "-":
            operation=new Minus();
            break;
        case "*":
            operation=new Multiplication();
            break;
        case "/":
            operation=new Division();
            break;
        }
        return  operation;
    }
}
複製代碼

4.建立測試類 運行 測試結果

複製代碼
public class FactoryTest {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("請輸入第一個數字:");
        double num1 = scanner.nextInt();
        System.out.println("請輸入運算符:");
        String operation = scanner.next();
        System.out.println("請輸入第二個數字:");
        double num2 = scanner.nextInt();
        //建立運算的實例對象
        Operation o = OperationFactory.getOperation(operation);
        //輸出結果
        System.out.println(o.getResult(num1, num2));
    }
}

 

 

11、做業

一、soso項目

二、週五考試(機考+筆試),刷題刷題!

三、隨時準備答辯soso項目

 

12、老師辛苦了!

相關文章
相關標籤/搜索