面向對象的思想
anything is Object(萬物皆對象)
抽象,從對具體的對象中抽取有用信息。
對象有其固有屬性,對象的方法,即對象的行爲(對象能做什麼)
對象本身是簡單的(功能簡單),多個對象可以組成複雜的系統(對象之間彼此調用對方的
方法)
對象應當是各司其職(功能簡單),各盡所能(把自己的功能作到最好)。(弱耦合性實現
了前面所述的對象的特點)
對象的耦合性,是對象之間的聯繫,對象和系統之間的聯繫。對象的耦合性要儘量的弱,也
就是對象之間的聯繫儘可能的弱,對象和系統之間的聯繫儘可能的弱。
系統的可插入性,是在系統中加入新的對象之後的系統穩定性。
對象的可替換性,是在系統中替換原有的對象之後的系統的穩定性。
複用性,即對象可否被重複使用,對象的功能越簡單,複用性就越好。(對象的耦合性弱,
複用性就比較強)
面向過程是先有算法,後又數據結構(怎麼解決問題)
面向對象是先有對象(數據結構),後有算法。(用什麼做)
類是某些有着相同屬性的集合的抽象。
類是一個類對象的模板,對象是類的具體化。
類是一個新的數據類型,類的對象。
注意:局部變量的作用範圍是在定義他的代碼塊以內,局部變量要先賦值後使用,在以一個重合的作用於範圍內不允許兩個局部變量命名衝突。局部變量局部優先,且在於實例變量同名時會副該局部變量。
變量 包括簡單變量(原始數據類型),對象變量。
方法的定義:
1,方法的修飾符(多個修飾符出現的順序無關) |
2,方法的返回值類型 |順
3,方法名 |序
4,方法的參數表 |向
5,方法中允許拋出的異常 |下
V
java中不能夠在返回語句後寫任何代碼。JVM+解釋器=JRE,JRE+類庫=JDK
java中方法的重載(overload)方法名相同,參數表不同,返回值類型可以不同。調用時要給出明確參數並確定調用某一方法。在編譯時,編譯器會根據參數選擇適當的方法,所以重載也叫編譯時多態。
就近向上匹配原則
如果方法的參數表中的數據類型和調用時給出的參數類型不盡相同時會根據向上匹配的就近原則。(類型就近向上轉化匹配)
注意:調用時要給出明確參數並確定調用某一方法,否則編譯會出錯。
對象使用者(調用其他對象的方法)對象(對象中的方法被調用時根據參數進行自己進行選擇)
一類方法,但跟據不同的參數會有差異,對象回根據參數判斷,對對象調用者透明。
創建對象的過程,1,分配空間 2,初始化屬性 3,調用構造方法(有前提,不考慮繼承關係)
構造方法的寫法,沒有返回值類型,構造方法的方法命名必須和類名相同。如果在類中不寫構造方法,系統會提供一個無參的構造方法。
注意:最好在寫類時提供一個無參的構造方法。
獲得對象的方式
通過new(在堆空間中申請分配空間),new 類名(),可以通過這種形式獲得一個對象,這時的對象是無法使
用,必須把的他的地址存放近一個對象變量才能夠使用。例如 :Car c=new Car();
有參的構造方法在被調用時,在用new關鍵字獲得對象時初始化,例如:Car c=new Car("yellow")
對象變量中存放的是對象的引用(地址的封裝形式)
this關鍵字,表示當前對象(哪個對象調用了方法,哪個對象就是當前對象),可以用來區分實例變量和局部變量。this(),他表示掉用本類其他的構造方法,注,只能寫在構造方法的第一行。
java中的參數傳遞,簡單類型的變量傳遞的是數值,對象變量的傳遞則傳遞的一個引用(地址)
面向對象的三大特徵:封裝、繼承、多態。
封裝,一個對象和外界的聯繫應當通過一個統一的接口,應當公開的公開,應當隱藏的隱藏。(對象的屬性應當隱藏),一個對象的內部是透明的,就是把對象內部的可透明性和隱藏的特性區分開,該透明的透明,該隱藏的隱藏。
(封裝的屬性)java中類的屬性的訪問權限的默認值不是private,要想隱藏該屬性或方法,就可以加private(私有)修飾符,來限制只能夠在類的內部進行訪問。
對於類中的私有屬性,要對其給出一對方法(getXxx(),setXxx())訪問私有屬性,保證對私有屬性的操作的安
全性。
方法的封裝,對於方法的封裝,該公開的公開,該隱藏的隱藏。方法公開的是方法的聲明(定義),即(只須知道參數和返回值就可以調用該方法),隱藏方法的實現會使實現的改變對架構的影響最小化。。
封裝會使方法實現的改變對架構的影響最小化。
完全的封裝,類的屬性全部私有化,並且提供一對函數來訪問屬性。
==================
day 04
=============
訪問控制符
public 全部可見
protected 本類可見,同包可見,子類可見
default 本類可見,同包可見
private 本類可見
繼承:父類的成員能否繼承到子類,子類能否訪問到父類的成員
父類的非私有化屬性(不同包的子類無法訪問default修飾符)和方法可以默認繼承到子類。
Class Son extends Father{
}
而如果父類中的私有方法被子類調用的話,則編譯報錯。
父類的構造方法子類不可以繼承,更不存在覆蓋的問題。
所以子類構造方法默認調用父類的無參構造方法。(所以養成寫無參構造的習慣)
如果子類訪問父類的有參構造方法,必須在子類構造方法第一行使用super(參數)
當構造一個對象的時候,系統先構造父類對象,再構造子類對象。
Public class BMWcar extends Car{
Public BMWcar(){
Super(int alength); //顯式的調用父類的構造,默認調用無參構造
//所以父類沒有無參構造的話,子類如果不加顯示調用其他構造就會報錯
。這裏的super是一個對父類的引用
}
}
private:本類內部可以訪問 不能繼承到子類
(default):本類內部可以訪問,同包其他類也可以訪問能否繼承到子類不一定,父子類同包可以訪問
protected:本類內部可以訪問,不同包的子類也可以訪問,同包其他類也可以訪問能繼承到子類
public:任何地方都可以訪問能繼承到子類
從嚴到寬
覆蓋:
方法名:相同
參數表:相同
訪問限制符:相同或者更寬
返回值類型:相同 或者 子類返回的類型是父類返回的類型的子類
對象的構造過程:
1.遞歸的構造父類對象
2.分配空間
3.初始化屬性
4.調用本類的某一個構造方法
super:調用父類的某一個構造方法super(),在構造方法中如果沒有this()和super()的話會隱含的有一行語句即super(),調用父類的無參構造方法。
父類對象super,在有權限訪問的前提下可以放文父類中的內容。
多態:
1. 對象不變
2. 只能對對象調用編譯時類型中定義的方法
3. 運行時,根據對象的運行時類型,找覆蓋過的方法來調用(運行時動態類型判定)
強制類型轉換 instanceof
多態的意義屏蔽子類的個性差異差異,利用父類共性做出通用編程
屬性的遮蓋(shadow)沒有多態,方法的重載看參數的編譯時類型
多態分兩種:
1編譯時多態:編譯時動態重載;
2運行時多態:指一個對象可以具有多個類型,方法的覆蓋
這樣對於對象而言分爲:
理解運行時多態:
Car c = new Bus();
Car編譯時類型 編譯時檢查變量類型是否存在,是否有調用的方法
Bus運行時類型 實際運行是訪問heep中的對象,調用實際的方法。
運行時多態是由運行時類型決定的
編譯時多態是由編譯時類型決定的
貓,小鳥,狗 都是動物,都可以安上動物的標籤。
Interface Animal{}
Class Car implements Animal{}
Class Bird implements Animal{}
Class Dog implements Animal{}
方法中
Animal a = new Car();
Animal b = new Bird();
Animal c = new Dog();
*方法重載看的是參數的編譯時類型
public class Animal{
public static void main(String[] args){
}
}
(1) 是覆蓋嗎?不能多態了
abstract class MyClass{
priavate void m();
}
class Sub extends MyClass(){
public void m();
}
(2) 錯誤的修飾符組合
abstract class MyClass{
priavate abstract void m();
}
class Sub extends MyClass(){
public void m();
}
(3) 5.0 新 非覆蓋
abstract class MyClass{
private final void m();
}
class Sub extends MyClass(){
public void m();
}
運行時多態的三原則
1.對象不變;(改變的是主觀認識)
2.對於對象的調用只能限於編譯時類型的方法,如調用運行時類型方法報錯。
在上面的例子中:Animal a=new Dog();對象a的編譯時類型爲Animal,運行時類型爲dog。
注意:編譯時類型一定要爲運行時類型的父類或者同類型。
對於語句:Dog d=(Dog)a。將d強制聲明爲a類型,此時d爲Dog(),此時d就可以調用運行時類型。注意:a和d指向同一對象。
3.動態類型判定實際調用的方法。即它調用覆蓋後的方法。
關係運算符:instanceof
instanceof Animal;(這個式子的結果是一個布爾表達式)
上面語句是判定a是否可以貼Animal標籤。如果可以貼則返回true,否則返回false。
在上面的題目中: a instanceof Animal返回 True,
a instanceof Dog也返回 True,
用於判定前面的對象是否是後邊的類或者子類。
Animal a = new Car();
If(a instanceof Dog){
Dog b =(Dog)a;
}
else if(a instanceof Car){
Car c =(Car)a
}
不會錯。
=======
day 05
===========
java中的修飾符
static 表示靜態,它可以修飾屬性,方法和代碼塊。
1,static修飾屬性(類變量),那麼這個屬性就可以用 類名.屬性名 來訪問,也就是使這個屬性成爲本類的類變量,爲
本類對象所共有。這個屬性就是全類公有。(共有的類變量與對象無關,只和類有關)。
類加載的過程,類本身也是保存在文件中(字節碼文件保存着類的信息)的,java會通過I/O流把類的文件(字節碼文件)讀入JVM(java虛擬機),這個過程成爲類的加載。JVM(java虛擬機)會通過類路徑(CLASSPATH)來找字節碼文件。
類變量,會在加載時自動初始化,初始化規則和實例變量相同。
注意:類中的實例變量是在創建對象時被初始化的,被static修飾的屬性,也就是類變量,是在類加載時被創建並進行初
始化,類加載的過程是進行一次。也就是類變量只會被創建一次。
2,static修飾方法(靜態方法),會使這個方法成爲整個類所公有的方法,可以用類名.方法名 訪問。
注意:static修飾的方法,不直接能訪問本類中的非靜態(static)成員(包括方法和屬性),本類的非靜態(static)方
法可以訪問本類的靜態成員(包括方法和屬性),可以調用靜態方法。靜態方法要慎重使用。在靜態方法中不能出現this
關鍵字。
注意:父類中是靜態方法,子類中不能覆蓋爲非靜態方法,在符合覆蓋規則的前提下,在父子類中,父類中的靜態方法可
以被子類中的靜態方法覆蓋,但是沒有多態。(在使用對象調用靜態方法是其實是調用編譯時類型的靜態方法)
注意:父子類中,靜態方法只能被靜態方法覆蓋,父子類中,非靜態方法只能被非靜態方法覆蓋。
java中的main方法必須寫成static的因爲,在類加載時無法創建對象,因爲靜態方法可以不通過對象調用
所以在類的main方法。所在在類加載時就可以通過main方法入口來運行程序。
3,static修飾初始代碼塊,這時這個初始代碼塊就叫做靜態初始代碼塊,這個代碼塊只在類加載時被執行一次。可以用靜態初始代碼塊初始化一個類。
動態初始代碼塊,寫在類體中的“{}”,這個代碼塊是在生成對象的初始化屬性是運行。這種代碼塊叫動態初始代碼塊。
類在什麼時候會被加載,創建對象時會加載類,調用類中靜態方法或訪問靜態屬性也是會加載類的。在加載子類時必會先
加載父類,類加載會有延遲加載原則,只有在必須加載時纔會加載。
final修飾符,可以修飾變量,方法,類
1,final修飾變量
被fianl修飾的變量就會變成常量(常量應當大寫),一旦賦值不能改變,(可以在初始化時直接賦值,也可以在構造方法裏也可以賦值,只能在這兩種方法裏二選一,不能不爲常量賦值),fianl的常量不會有默認初始值,對於直接在初始化是賦值時final修飾符常和static修飾符一起使用。
2,final修飾方法,被final修飾的方法將不能被其子類覆蓋,保持方法的穩定不能被覆蓋。
3,final修飾類,被final修飾的類將不能被繼承。final類中的方法也都是final的。
注意:final,不能用來修飾構造方法,在父類中如果有常量屬性,在子類中使用常量屬性時是不會進行父類的類加載。
不變模式,對象一旦創建屬性就不會改變。用final修飾屬性,也用final修飾類(強不變模式),用final修飾屬性(弱不變模式)。
不變模式的典型體現:java.lang.String類,不變模式可以實現對象的共享(可以用一個對象實例賦值給多個對象變量。
)
池化的思想,把需要共享的數據放在池中(節省空間,共享數據)
只有String類可以用“”中的字面值創建對象。在String類中,以字面值創建時,會到Java方法空間的串池空間中去查找
,如果有就返回串池中字符串的地址,並把這個地址付給對象變量。如果沒有則會在串池裏創建一個字符串對象,並返回
其地址付購對象變量,當另一個以字面值創建對象時則會重複上述過程。
如果是new在堆空間中創建String類的對象,則不會有上述的過程。
String類中的intern()方法會將在堆空間中創建的String類對象中的字符串和串池中的比對,如果有相同的串就返回這個
串的串池中的地址。
不變模式在對於對象進行修改,添加操作是使相當麻煩的,他會產生很多的中間垃圾對象。創建和銷燬的資源的開銷是相
當大的。
String類在字符串連接時會先的效率很低,就是因爲它所產生的對象的書性是不能夠修改的,當連接字符串時也就是隻能
創建新的對象。
對於很多的字符串連接,應當使用StringBuffer類,在使用這個類的對象來進行字符串連接時就不會有多餘的中間對象生
成,從而優化了效率。
abstract(抽象)修飾符,可以修飾類和方法
1,abstract修飾類,會使這個類成爲一個抽象類,這個類將不能生成對象實例,但可以做爲對象變量聲明的類型,也就是編譯時類型,抽象類就像當於一類的半成品,需要子類繼承並覆蓋其中的抽象方法。
2,abstract修飾方法,會使這個方法變成抽象方法,也就是隻有聲明(定義)而沒有實現,實現部分以";"代替。需要子
類繼承實現(覆蓋)。
注意:有抽象方法的類一定是抽象類。但是抽象類中不一定都是抽象方法,也可以全是具體方法。
abstract修飾符在修飾類時必須放在類名前。
abstract修飾方法就是要求其子類覆蓋(實現)這個方法。調用時可以以多態方式調用子類覆蓋(實現)後的方法,也就
是說抽象方法必須在其子類中實現,除非子類本身也是抽象類。
注意:父類是抽象類,其中有抽象方法,那麼子類繼承父類,並把父類中的所有抽象方法都實現(覆蓋)了,子類纔有創
建對象的實例的能力,否則子類也必須是抽象類。抽象類中可以有構造方法,是子類在構造子類對象時需要調用的父類(
抽象類)的構造方法。
final和abstract,private和abstract,static和abstract,這些是不能放在一起的修飾符,因爲abstract修飾的方法是
必須在其子類中實現(覆蓋),才能以多態方式調用,以上修飾符在修飾方法時期子類都覆蓋不了這個方法,final是不可以覆蓋,private是不能夠繼承到子類,所以也就不能覆蓋,static是可以覆蓋的,但是在調用時會調用編譯時類型的方法,因爲調用的是父類的方法,而父類的方法又是抽象的方法,又不能夠調用,所以上的修飾符不能放在一起。
抽象(abstract)方法代表了某種標準,定義標準,定義功能,在子類中去實現功能(子類繼承了父類並需要給出從父類
繼承的抽象方法的實現)。
方法一時間想不到怎麼被實現,或有意要子類去實現而定義某種標準,這個方法可以被定義爲抽象。(abstract)
模板方法模式
用abstract把制訂標準和實現標準分開,制定的標準就是模板,實現就是按模板標準來實現,也就是繼承模板,實現模板
中相應功能的方法。模板中不允許修改的方法可以用fianl來修飾,這個方法不能使抽象方法,爲保證安全,封裝,把模板中不公開的部分用protected(保護)修飾。
===========
day 06
=================
java中的接口
接口是一種程序結構,是特殊的抽象類。接口中的方法必須都是公開的抽象方法(public abstract),接口中的屬性都是公開靜態常量(public static final)。
聲明一個接口用 interface 關鍵字,接口也是一種類型,編譯之後也有生成相應字節碼,他的聲明規範也要符合類型的定義(一個源文件中只能有一個public interface,接口名和源文件名相同,有public interface,就不能在寫public class了)。接口中的屬性可以不加修飾符,方法也不用加修飾符。
接口也可以繼承,但是隻能由接口繼承,在用類去繼承時要換用 implements 關鍵字,這時類和接口也不叫做繼承關係,而是實現關係,但其實質也是繼承。
一個類可以繼承也只能繼承另外一個類,但是可以實現多個接口,其語法是在implements後面寫接口名,多個接口以“,”分隔。
接口之間是可以多繼承的,其語法和類的繼承語法是相同的,在接口多繼承時,在extends後寫接口名如果要繼承多個接口,接口名以“,”分隔,接口的繼承關係只是把其父接口中的抽象方法繼承到子接口中。要實現接口就必須實現接口中的所有方法。
一個類可以在繼承一個類的同時,也可以實現一個或多個接口。採用接口就繞開了單繼承限制。
接口類型也可以做爲編譯時類型使用,但其實際的運行時類型必須是完全實現接口的類的對象實例,這樣就使多態變得很靈活了,
注意:實現接口時,在實現(覆蓋)抽象方法時,注意必須要在方法的返回值類型前加public修飾符。如果沒有完全實現接口中的方法,那麼這個類就只能夠是個抽象類,不能創建對象。接口的是實質就是特殊的抽象類。接口沒有構造方法。
接口的意義:
1,接口可以實現多繼承。
2,用接口可以實現混合類型(主類型,副類型),java中可以通過接口分出主次類型。主類型使用繼承,副類型,使用接口實現。
3,接口進一步深化了標準的思想,接口本身就是一個標準,他起到了降低耦合性的作用,接口可以使方法的定義和實現相分離,也就是將接口的定義者和實現者相分離,接口也可以用於降低模塊間或系統間的耦合性。針對接口編程可以屏蔽不同實現間的差異,看到的只是實現好的功能,
接口:定義標準,
接口的實現:實現標準
接口的使用:標準的使用
針對接口編程原則,也就是按照標準實現。
先有接口的定義,再有接口使用者,最後把接口的是先對象川入接口的使用者中,接口的使用者會通過接口來調用接口實現者的方法。
接口的定義者定義好了標準,接口的使用者先寫好了使用代碼,接口的實現者寫好實現之後把實現對象傳入接口的使用者中。他會回調接口中的方法。這種過程叫做接口的回調。
儘量使用接口類型作爲編譯時類型,儘量將抽取到的共性行爲寫在接口中。
用若干個小接口取代一個大接口。(接口隔離原則)
把一個類的功能作成接口,只暴露想暴露的方法,接口隔離原則可以實現更高層次的封裝,針對的對象不同,暴露的方法也不同。
java中的根類Object
java中所有的類的父類或直接或間接的或隱含的都是Object類。
java不允許循環繼承,也就是互相繼承是不可以的。
Object類中的finalize()一個對象被垃圾收集的時候,
Object類中有一個String toString()方法,返回該對象的字符串表示。Object類中的toString()方法他返回的是類名加上他的地址的一個字符串。在子類中推薦覆蓋toString()方法。
Object類中的boolean equals(Object o)方法是用來比較對象的內容是否相等,其返回值是boolean類型的值,相同爲真,不同則爲假。實際上還是比較對象地址是否相同。String類覆蓋了equals()方法,他比較是對象中的內容是否相同。子類中也推薦覆蓋Object類中繼承的equals()方法
equals()的覆蓋原則,
自反性 x.equals(x) 爲true
對稱性 y.equals(x) 和 x.equals(y) 的值要相同,要麼都爲true,要麼都爲false。
傳遞性 x.equals(y)爲true, y.equals(z)也爲true ,那麼x.equals(z)一定也爲true。
覆蓋equals()方法的步驟
boolean equals(Object o){
if(this==o) return true;//1,看看是不是一個對象
if(o==null) return true;//2,看看對象是不是空
if(!(o instanceof 本類類名)) return false;//看看是不是本類對象
......//根據本類設計。
}
代碼:
--------------------------------------------------------------------------------
=============
1. 接口作爲副類型
public class TestEmployee{
public static void main(String[] args){
Employee[] es=new Employee[4];
es[0]=new SalariedEmployee("Liucy",8,5000);
es[1]=new HourlyEmployee("Chenzq",2,40,200);
es[2]=new SalesEmployee("DuBin",8,0.03,80000);
es[3]=new BasePlusSalesEmployee("Winnie",10,0.08,150000,8000);
for(int i=0;i<es.length;i++){
System.out.println(es[i].getName()+": "+es[i].getSalary(
8));
}
//判斷對象是否是Plusable對象,可以加班的對象
//強制轉成Plusable,計算加班費
double d=0;
for(int i=0;i<es.length;i++){
if (es[i] instanceof Plusable){
Plusable p=(Plusable)es[i];
d+=p.getPlusSalary();
}
}
System.out.println(d);
}
}
class Employee{
private String name;
private int month;
public Employee(String name, int month) {
this.name = name;
this.month = month;
}
public String getName() {
return name;
}
//一般員工的共性部分,判斷生日
public double getSalary(int month){
if(this.month==month) return 100;
else return 0;
}
}
interface Plusable{
double getPlusSalary();
}
class SalariedEmployee extends Employee implements Plusable{
private double salary;
//構造參數設置父類屬性
public SalariedEmployee(String name, int month,double salary) {
super(name, month);
this.salary=salary;
}
public double getSalary(int month){
return salary+super.getSalary(month)+getPlusSalary();
}
public double getPlusSalary(){
return 1000;
}
}
class HourlyEmployee extends Employee{
private double salaryPerHour;
private int hours;
public HourlyEmployee(String name, int month, double salaryPerHour, int hours) {
super(name, month);
this.salaryPerHour = salaryPerHour;
this.hours = hours;
}
public double getSalary(int month){
double r=0;
if (hours>160){
r=160*this.salaryPerHour+(hours-160)*1.5*this.salaryPerHour;
}
else {
r=this.hours*this.salaryPerHour;
}
return r+super.getSalary(month);
}
}
class SalesEmployee extends Employee implements Plusable{
private double rate;
private int sales;
public SalesEmployee(String name, int month, double rate, int sales) {
super(name, month);
this.rate = rate;
this.sales = sales;
}
public double getSalary(int month){
return rate*sales+super.getSalary(month)+getPlusSalary();
}
public double getPlusSalary(){
return 100;
}
}
class BasePlusSalesEmployee extends SalesEmployee{
private double baseSalary;
public BasePlusSalesEmployee(String name, int month, double rate, int sales, double baseSalary) {
super(name, month, rate, sales);
this.baseSalary = baseSalary;
}
public double getSalary(int month){
return baseSalary+super.getSalary(month);
}
}
=======
2. 相當於一個標準,實現解藕合,把接口的使用者與實現者分開
//判斷一個數是不是合數,是合數的打印出其質數積的形式
// 定義了兩個接口
// Prime.java
public interface Prime{
boolean isPrime(int i);
}
// FenJie.java
public interface FenJie{
void print(int i);
}
// FenJieImpl.java 實現接口 FenJie
public class FenJieImpl implements FenJie{
Prime p;
public FenJieImpl(Prime p){
this.p=p;
}
public void print(int i){
for(int j=2;j<=i/2;j++){
if (i%j==0 && p.isPrime(j)){
int k=i/j;
if (p.isPrime(k)){
System.out.println(j+"*"+k);
}
else{
System.out.print(j+"*");
print(k);
}
break;
}
}
}
}
//PrimeImpl.java 實現接口Prime
public class PrimeImpl implements Prime{
public boolean isPrime(int i){
for(int j=2;j<i;j++){
if (i%j==0) return false;
}
return true;
}
}
// Print.java 使用接口
public class Print{
public static void main(String[] args){
Prime p=new PrimeImpl();
FenJie f=new FenJieImpl(p);
MyClass mc=new MyClass(p,f);
mc.business();
}
}
// 使用接口
class MyClass{
Prime p;
FenJie f;
public MyClass(Prime p,FenJie f){
this.p=p;
this.f=f;
}
public void business(){
for(int i=2;i<=100;i++){
if (!(p.isPrime(i))){
System.out.print(i+"=");
f.print(i);
}
}
}
}
3. 接口的回調
代碼:
--------------------------------------------------------------------------------
---------------
// WorldCupCountry.java 定義接口
public interface WorldCupCountry{
void kaimushi();
void xiaozusai();
void taotaisai();
void juesai();
}
// WorldCupCountry.java 實現接口
public class USA implements WorldCupCountry{
public void kaimushi(){
System.out.println("德國-玻利維亞");
}
public void xiaozusai(){
System.out.println("沙特黑馬");
}
public void taotaisai(){
System.out.println("保加利亞");
}
public void juesai(){
System.out.println("巴西");
}
}
// Germany.java 實現接口
public class Germany implements WorldCupCountry{
public void kaimushi(){
System.out.println("德國-哥斯達黎加");
}
public void xiaozusai(){
System.out.println("強者恆強");
}
public void taotaisai(){
System.out.println("四強全歐");
}
public void juesai(){
System.out.println("意大利");
}
}
// IFFO.java 使用接口
public class FIFA{
public static void main(String[] args){
WorldCupCountry c=new USA();
act(c);
}
public static void act(WorldCupCountry c){
c.kaimushi();
c.xiaozusai();
c.taotaisai();
c.juesai();
}
}
Object 類
toString() , equals() 方法的使用
================
代碼:
--------------------------------------------------------------------------------
public class TestObject{
public static void main(String[] args){
/*
Student s=new Student("Liucy");
System.out.println(s);
*/
/*
String s1=new String("ABC");
String s2=new String("ABC");
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
*/
Student s1=new Student("Liucy",30);
Student s2=new Student("Liucy",30);
System.out.println(s1.equals(s2));
}
}
class Student{
String name;
int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
//覆蓋 toString() 方法,繼承的該方法返回對像的字符串表現形式
public String toString(){
return "Student "+name;
}
// 覆蓋 equals() 方法, 用來判斷兩個對象的值是否相等
public boolean equals(Object o){
if (this==o) return true;
if (o==null) return false;
if (!(o instanceof Student)) return false;
Student s=(Student)o;
if (this.age==s.age && this.name.equals(s.name)) return true;
else return false;
}
}
=========
day 07
===============
封裝類
JAVA爲每一個簡單數據類型提供了一個封裝類,使每個簡單數據類型可以被Object來裝載。
除了int(Integer)和char(Character),其餘類型首字母大寫即成封裝類類型名。
轉換字符的方式:
int I=10;
String s=I+” ”;
String s1=String.valueOf(i);
Int I=10;
Interger I_class=new integer(I);
封裝類.字符串.基本類型
Interger--------------------(Double(x.toString))------------>Double
String -----------------(Integer.valueOf() )---------------->Integer
Integer-----------------(x.toString() )--------------------->String
int----------------------(100+””)------------------------->String
String------------------(Integer.parseInt() )--------------->int
Integer-----------------(Integer.intvalue() )--------------->int
學會查看javadoc的幫助文檔。要先關注要使用方法的返回值類型,也就是要獲得內容的類型,然後看方法名,JDK中的方法名基本上是見名知義,參數表,就是看需要什麼纔可以獲得的需要的那些內容,也要看自己能夠提供什麼。
注意:“==”在任何時候都是比較地址,這種比較永遠不會被覆蓋。
程序員自己編寫的類和JDK類是一種合作關係。(因爲多態的存在,可能存在我們調用JDK類的情況,也可能存在JDK自動調
用我們的類的情況。)
注意:類型轉換中double/interger/string之間的轉換最多。
(注:所有使用內部類的地方都可以不用內部類,但使用內部類可以使程序更加的簡潔,便於命名規範和劃分層次結構)。
內部類是指在一個外部類的內部再定義一個類。
*內部類可爲靜態,可用PROTECTED和PRIVATE修飾。(而外部類不可以:頂級類只能使用PUBLIC和DEFAULT)。
*JAVA文件中沒有publie class 可以類名和文件不同名。
內部類
內部類也就是定義在類內部的類。
內部類的分類
成員內部類、
局部內部類、
靜態內部類、
匿名內部類(圖形是要用到,必須掌握)。
成員內部類
四個訪問權限修飾符都可以修飾成員內部類。
內部類和外部類在編譯時時不同的兩個類,內部類對外部類沒有任何依賴。
內部類是一種編譯時語法,在編譯時生成的各自的字節碼文件,內部類和外部類沒有關係。
內部類中可以訪問外部類的私有成員。
作爲外部類的一個成員存在,與外部類的屬性、方法並列。
內部類和外部類的實例變量可以共存。
在內部類中訪問實例變量:this.屬性
在內部類訪問外部類的實例變量:外部類名.this.屬性。
在外部類的外部訪問內部類,使用out.inner.
成員內部類的特點:
1.內部類作爲外部類的成員,可以訪問外部類的私有成員或屬性。(即使將外部類聲明爲private,但是對於處於其內部的內部類還是可見的。)
2.用內部類定義在外部類中不可訪問的屬性。這樣就在外部類中實現了比外部類的private還要小的訪問權限。
注意:內部類是一個編譯時的概念,一旦編譯成功,就會成爲完全不同的兩類。
對於一個名爲outer的外部類和其內部定義的名爲inner的內部類。編譯完成後出現outer.class和outer$inner.class兩類。
3.成員內部類不能含有靜態成員。
建立內部類對象時應注意:
在外部類的內部可以直接使用inner s=new inner();(因爲外部類知道inner是哪個類,所以可以生成對象。)
而在外部類的外部,要生成(new)一個內部類對象,需要首先建立一個外部類對象(外部類可用),然後在生成一個內部
類對象。內部類的類名是外部類類名.內部類類名。
Outer o=new Outer();
Outer.Inner in=o.new.Inner()。
靜態內部類
(注意:前三種內部類與變量類似,所以可以對照參考變量)
靜態內部類定義在類中,任何方法外,用static class定義。
靜態內部類只能訪問外部類的靜態成員。
生成(new)一個靜態內部類不需要外部類成員:這是靜態內部類和成員內部類的區別。
靜態內部類的對象可以直接生成:
Outer.Inner in=new Outer.Inner();
而不需要通過生成外部類對象來生成。這樣實際上使靜態內部類成爲了一個頂級類。靜態內部類不可用private來進行定義
。
注意:當類與接口(或者是接口與接口)發生方法命名衝突的時候,此時必須使用內部類來實現。
用接口不能完全地實現多繼承,用接口配合內部類才能實現真正的多繼承。
例子:
對於兩個類,擁有相同的方法:
class People
{
run();
}
interface Machine{
run();
}
此時有一個robot類:
class Robot extends People implement Machine.
此時run()不可直接實現。
interface Machine
{
void run();
}
class Person
{
void run(){System.out.println("run");}
}
class Robot extends Person
{
private class MachineHeart implements Machine
{
public void run(){System.out.println("heart run");}
}
public void run(){System.out.println("Robot run");}
Machine getMachine(){return new MachineHeart();}
}
class Test
{
public static void main(String[] args)
{
Robot robot=new Robot();
Machine m=robot.getMachine();
m.run();
robot.run();
}
}
局部內部類
在方法中定義的內部類稱爲局部內部類。
與局部變量類似,在局部內部類前不加修飾符public和private,其範圍爲定義它的代碼塊。
注意:局部內部類不僅可以訪問外部類私有實例變量,但可以訪問外部類的局部常量(也就是局部變量必須爲final的)
在類外不可直接訪問局部內部類(保證局部內部類對外是不可見的)。
在方法中才能調用其局部內部類。
通過內部類和接口達到一個強制的弱耦合,用局部內部類來實現接口,並在方法中返回接口類型,使局部內部類不可見,屏蔽實現類的可見性。
局部內部類寫法
public class TestLocalInnerClass{
public static void main(String[] args){
Outer o=new Outer();
final int a=9;
o.print(a);
}
}
class Outer{
private int index=100;
public void print(final int a){
final int b=10;
System.out.println(a);
class Inner{
public void print(){
System.out.println(index);
System.out.println(a);
System.out.println(b);
}
}
Inner i=new Inner();
i.print();
}
}
匿名內部類
匿名內部類是一種特殊的局部內部類,它是通過匿名類實現接口。
匿名內部類的特點:
1,一個類用於繼承其他類或是實現接口,並不需要增加額外的方法,只是對繼承方法的事先或是覆蓋。
2,只是爲了獲得一個對象實例,不許要知道其實際類型。
3,類名沒有意義,也就是不需要使用到。
注:一個匿名內部類一定是在new的後面,用其隱含實現一個接口或實現一個類,沒有類名,根據多態,我們使用其父類名
。
因其爲局部內部類,那麼局部內部類的所有限制都對其生效。
匿名內部類是唯一一種無構造方法類。
大部分匿名內部類是用於接口回調用的。
匿名內部類在編譯的時候由系統自動起名Out$1.class。
如果一個對象編譯時的類型是接口,那麼其運行的類型爲實現這個接口的類。
因匿名內部類無構造方法,所以其使用範圍非常的有限。
當需要多個對象時使用局部內部類,因此局部內部類的應用相對比較多。匿名內部類中不能定義構造方法。
匿名內部類的寫法:
interface A{
void ia();
}
class B{
public A bc(){
return new A{
void ia(){
}
};
}
}
使用匿名內部類:
B b=new B();
A a=b.bc();
a.ia();
Exception(例外/異常)
對於程序可能出現的錯誤應該做出預案。
例外是程序中所有出乎意料的結果。(關係到系統的健壯性)
JAVA會將所有的異常封裝成爲一個對象,其根本父類爲Throwable。
異常的分類
Throwable有兩個子類:Error和Exception。
一個Error對象表示一個程序錯誤,指的是底層的、低級的、不可恢復的嚴重錯誤。此時程序一定會退出,因爲已經失去了
運行所必須的物理環境。對於Error錯誤我們無法進行處理,因爲我們是通過程序來應對錯誤,可是程序已經退出了。
我們可以處理的Throwable類中只有Exception類的對象(例外/異常)。
Exception有兩個子類:Runtime exception(未檢查異常)可以在編程時避免,可處理可不處理
非Runtime exception(已檢查異常)必須進行處理。
注意:無論是未檢查異常還是已檢查異常在編譯的時候都不會被發現,在編譯的過程中檢查的是程序的語法錯誤,而異常是一個運行時程序出錯的概念。
在Exception中,所有的非未檢查異常都是已檢查異常,沒有另外的異常!!
未檢查異常是因爲程序員沒有進行必要的檢查,因爲他的疏忽和錯誤而引起的異常。一定是屬於虛擬機內部的異常(比如空指針)。
應對未檢查異常就是養成良好的檢查習慣。
已檢查異常是不可避免的,對於已檢查異常必須實現定義好應對的方法。
已檢查異常肯定跨越出了虛擬機的範圍。(比如“未找到文件”)
異常的傳遞
如何處理已檢查異常(對於所有的已檢查異常都要進行處理):
首先了解異常形成的機制:
當一個方法中有一條語句出現了異常,它就會throw(拋出)一個例外對象(throw 異常對象),然後後面的語句不會執行
返回上一級方法,其上一級方法接受到了例外對象之後,有可能對這個異常進行處理,也可能將這個異常轉到它的上一級。
注意:當一個方法中出現了異常,沒有進行異常處理,方法就會把異常對象作爲返回值返回。如果有異常進入虛擬機,那麼虛擬機就會立刻中止程序的執行。
異常的處理方式
非RuntimeException (已檢查異常)這種異常必須處理。如果不處理編譯出錯。
對於接收到的已檢查異常有兩種處理方式:throws和try..catch(...){}方法。
注意:出錯的方法有可能是JDK,也可能是程序員寫的程序,無論誰寫的,拋出一定用throw。
在方法的定義中聲明方法可能拋出的異常,用(throws 異常類名,異常類名) ,聲明這個方法將不處理異常,並把異常交給上一級方法處理。可以拋出的是實際產生異常的父類的異常對象。
例:public void print() throws Exception.
對於方法a,如果它定義了throws Exception。那麼當它調用的方法b返回異常對象時,方法a並不處理,而將這個異常對象
向上一級返回,如果所有的方法均不進行處理,返回到主方法,程序中止。(要避免所有的方法都返回的使用方法,因爲這樣出現一個很小的異常就會令程序中止)。
如果在方法的程序中有一行throw new Exception(),返回錯誤,那麼其後的程序不執行。因爲錯誤返回後,後面的程序肯
定沒有機會執行,那麼JAVA認爲以後的程序沒有存在的必要。
try..catch捕獲異常
對於try……catch格式:
try {可能出現錯誤的代碼塊} catch(exception e){進行處理的代碼} ;
對象變量的聲明
用這種方法,如果代碼正確,那麼程序不經過catch語句直接向下運行;
如果代碼不正確,則將返回的異常對象和e進行匹配,如果匹配成功,則處理其後面的異常處理代碼。(如果用exception來聲明e的話,因爲exception爲所有exception對象的父類,所有肯定匹配成功)。處理完代碼後這個例外就完全處理完畢,
程序會接着從出現異常的地方向下執行(是從出現異常的地方還是在catch後面呢?利用程序進行驗證)。最後程序正常退
出。
try塊中的代碼如果沒有出現異常,就會跳過catch,正常執行。
try中如果發現錯誤,即跳出try塊去匹配catch,那麼try後面的語句就不會被執行。
一個try可以跟進多個catch語句,用於處理不同情況。當一個try只能匹配一個catch。
我們可以寫多個catch語句,但是不能將父類型的exception的位置寫在子類型的excepiton之前,因爲這樣父類型肯定先於
子類型被匹配,所有子類型就成爲廢話,java中是不允許寫廢話的,所以編譯會出錯。
在try,catch後還可以再跟一子句finally。其中的代碼語句無論如何(無論有沒有異常)都會被執行(因爲finally子句的這個特性,所以一般將釋放資源,關閉連接的語句寫在裏面)。finally中的代碼在和try中的代碼的衝突時,finally中的
代碼一定會被執行且會忽略try中的代碼。但是System.exit(0);(虛擬機退出語句)則不會去執行fianlly中的代碼。
try{..}catch(..){..}
try{..}catch(..){}finally{..}
try{..}finally{}
以上三種寫法都可以。
如果在程序中書寫了檢查(拋出)exception但是沒有對這個可能出現的檢查結果進行處理,那麼程序就會報錯。而如果只
有處理情況(try)而沒有相應的catch子句,則編譯還是通不過。
如何知道在編寫的程序中會出現例外呢
1.調用方法,查看API中查看方法中是否有已檢查錯誤。
2.在編譯的過程中看提示信息,然後加上相應的處理。
Throwable有一個message屬性。在使用catch的時候可以調用:
Catch(IOException e){System.out.println(e.message())};
Catch(IOException e){e.printStackTrace()};
以上兩條語句都是可以打印出錯的過程信息。告訴我們出錯類型所歷經的過程,在調試的中非常有用。
開發中的兩個道理:
①如何控制try的範圍:根據操作的連動性和相關性,如果前面的程序代碼塊拋出的錯誤影響了後面程序代碼的運行,那麼
這個我們就說這兩個程序代碼存在關聯,應該放在同一個try中。
②對已經查出來的例外,有throw(消極)和try catch(積極)兩種處理方法。
對於throws把異常拋到try catch能夠很好地處理例外的位置(即放在具備對例外進行處理的能力的位置)。如果沒有處理
能力就繼續上拋。
當我們自己定義一個例外類的時候必須使其繼承excepiton或者RuntimeException。
throw是一個語句,用來做拋出例外的功能。
而throws是表示如果下級方法中如果有例外拋出,那麼本方法不做處理,繼續向上拋出。
throws後跟的是例外類型。
注意:方法的覆蓋中,如果子類的方法拋出的例外是父類方法拋出的例外的父類型,那麼編譯就會出錯:子類無法覆蓋父類。
結論:子類方法不可比父類方法拋出更多的例外。子類拋出的例外或者與父類拋出的例外一致,或者是父類拋出例外的子類型。或者子類型不拋出例外。如果父類型無throws時,子類型也不允許出現throws。此時只能使用try catch。
斷言是一種調試工具(assert)
其後跟的是布爾類型的表達式,如果表達式結果爲真不影響程序運行。如果爲假系統出現低級錯誤,在屏幕上出現assert信息。
Assert只是用於調試。在產品編譯完成後上線assert代碼就被刪除了。
代碼:
--------------------------------------------------------------------------------
內部類
1. 成員內部類
--------
public class TestMemberInnerClass{
public static void main(String[] args){
Outer out=new Outer();
Outer.Inner in=out.new Inner();
in.print();
}
}
class Outer{
private int index=200;
class Inner{
private int index=100;
public void print(){
int index=50;
System.out.println(index);
System.out.println(this.index);
System.out.println(Outer.this.index);
}
}
}
2. 靜態內部類
---------------
public class TestStaticInnerClass{
public static void main(String[] args){
Outer.Inner in =new Outer.Inner();
in.print();
}
}
class Outer{
private static int index=100;
static class Inner{
private int index=50;
public void print(){
System.out.println(index);
System.out.println(Outer.index);
}
}
}
3. 局部內部類
-------------
public class TestLocalInnerClass{
public static void main(String[] args){
Outer out=new Outer();
out.print(10);
}
}
class Outer{
private int index=100;
public void print(final int a){
final int b=20;
class Inner{
public void method(){
System.out.println(index);
System.out.println(a);
System.out.println(b);
}
}
Inner in=new Inner();
in.method();
}
}
----------------
必需使用內部類的情況: 父類與接口中的方法命名衝突時
public class TestRobot{
public static void main(String[] args){
Robot r=new Robot();
r.run();
r.getHeart().run();
}
}
abstract class People{
abstract void run();
}
interface Machine{
void run();
}
class Robot extends People{
class Heart implements Machine{
public void run(){
System.out.println("發動機運行");
}
}
public Machine getHeart(){
return new Heart();
}
public void run(){
System.out.println("機器人跑");
}
}
--------------------
代碼:
--------------------------------------------------------------------------------
局部內部類經常配合接口使用,來強制實現弱藕合,強制實現者針對接口編程
------------
public class TestInnerClass{
public static void main(String[] args){
//Teacher t=Tarena.getTeacher("CoreJava");
//t.teach();
/*
Liuxf t=new Liuxf();
t.teach();
*/
Tarena.run(new Teacher(){
public void teach(){
System.out.println("HeHe");
}
});
}
}
interface Teacher{
void teach();
}
class Tarena{
/*
public static Teacher getTeacher(String course){
class Liuxf implements Teacher{
public void teach(){
System.out.println("多講項目經驗");
}
}
class Huxz implements Teacher{
public void teach(){
System.out.println("重在思想,重在理解,強調編碼能力");
}
}
if (course.equals("CoreJava")) return new Huxz();
else return new Liuxf();
}
*/
public static Teacher getTeacher(String course){
if (course.equals("CoreJava")){
return new Teacher(){
public void teach(){
System.out.println("CoreJava Teacher");
}
};
}
else {
return new Teacher(){
public void teach(){
System.out.println("OtherTeacher");
}
};
}
}
public static void run(Teacher t){
t.teach();
}
}
---------------------
封裝類:
public class TestInteger{
public static void main(String[] args){
int i=12;
Integer ii=new Integer(i);
int i2=ii.intvalue();
String s=String.valueOf(i);
String s2=i+"";
int i3=Integer.parseInt(s);
String s3=ii.toString();
Integer ii2=Integer.valueOf(s3);
}
}
--------------
異常處理:
1. runtimeException
public class TestRuntimeException{
public static void main(String[] args){
/*
double a=1;
double b=0;
System.out.println(a/b);
*/
/*
int[] a=new int[3];
int i=2;
if (i>=0 && i<a.length) System.out.println(a[i]);
*/
/*
Animal a=new Dog();
if (a instanceof Cat) Cat c=(Cat)a;
*/
Animal a=null;
a.eat();
}
}
class Animal{
public void eat(){}
}
class Dog extends Animal{}
class Cat extends Animal{}
---------
代碼:
--------------------------------------------------------------------------------
-----------
非 runtimeException
import java.io.*;
import java.sql.*;
import java.net.*;
public class TestException{
public static void main(String[] args){
System.out.println("Main 1");
int i=Integer.parseInt(args[0]);
ma(i);
System.out.println("Main 2");
}
public static void ma(int a){
System.out.println("MA 1");
try{
mb(a);
System.out.println("MA 2");
}
catch(SQLException e){
e.printStackTrace();
}
catch(IOException e){
e.printStackTrace();
}
catch(MyException e){
e.printStackTrace();
}
catch(Exception e){
e.printStackTrace();
}
finally{
System.out.println("Finally");
}
System.out.println("MA 3");
}
public static void mb(int a) throws SQLException,IOException,MyException{
System.out.println("MB 1");
mc(a);
System.out.println("MB 2");
}
public static void mc(int a)throws EOFException,SocketException,SQLException,MyException{
System.out.println("MC 1");
if (a==0) throw new NullPointerException("空指針");
if (a==1) throw new EOFException("文件結束異常");
if (a==2) throw new SocketException("套接字異常");
if (a==3) throw new SQLException("數據庫異常");
if (a==4) throw new MyException("我自定義的異常");
System.out.println("MC 2");
}
}
class MyException extends Exception{
public MyException(String message){
super(message);
}
public MyException(){}
}
---------
finally 的用法
public class TestFinally{
public static void main(String[] args){
System.out.println(fn(1));
System.out.println(fn(0));
System.out.println(fn(2));
}
public static int fn(int b){
try{
return 2/b;
}
catch(Exception e){
return 0;
}
finally{
if (b==2) return 2;
}
}
}
----------------
day 08
================
集合類
集合類的對象是用來管理其他若干對象的,它類似於C++標準模板庫中的容器,不過在JAVA的集合類的對象中可以用來存放多種類型的對象。
接口和類共同構成了一個集合框架,集合的概念,一個對象可以裝載多個對象,這個對象就是集合對象。
集合框架
1,接口
Collection 用來管理多個對象,集合中的每個元素都是對象。
Map,Map中沒有對象,而是鍵值對,由Key,value組成的鍵值對,Key是不可重複的。value是可以相同的,一個Key和一
個value一一對應。
集合中用到的類,接口在java.util包中,在使用時注意將其引入import。
Collection 接口(以下介紹其子接口)
1)List 一個List的實現類的對象在管理多個對象時會按順序組織對象(即按照將對象放入的順序存儲),List實現類的對象是由順序的。(注意,順序和排序的區別)
2)Set 一個Set的實現類表示一個數學概念上的集合,Set的實現類的對象中的元素是無順序的,也就是不會按照輸入順
序來存放,Set的實現類對象中的元素是不重複的。
3)SortedSet,他是Set的子接口,他的實現類會對集合中的元素進行排序。但是要指定排序規則,他會按排序規則進行排序。
Map 接口(以下介紹其子接口)
SortedMap,這個接口的實現類同樣可以實現,不過是對鍵值對中的Key進行排序,這個接口的實現類也是要指定排序規
則的。
JDK1.4中的集合是不安全的對象,JDK5.0中解決了這個問題。
List接口的實現類
1> ArrayList是接近於功能的集合類,ArryList的實質就是一個會自動增長的數組,ArrayList是用封裝的數組來實現的List接口的。
Collection的實現類對象的遍歷方式是用迭代來實現的。
在使用迭代器時先要活得一個迭代器的對象,Iterator(迭代器接口)這是一個接口,迭代器是在集合類中實現的,也
就是說,他是一個內部類(匿名內部類)實現的。
Iterator接口中定義的常用方法方法hasNext(),next()。
hasNext(),這個方法會使用一個遊標,並通過判斷遊標指向的位置是否存放有對象。
next()方法也是Iterator接口中定義好的方法,這個方法會使遊標指向下一個元素的位置,遊標會跳過第一個元素,並
返回其中的內容。
Collections 這是一個工具類,也是java.util包中的,這個類中的sort(list接口的實現類的對象)方法,其參數是一個集合類的對象,這個方法使用來對集合類的對象進行排序的。以後,我將以集合這個名字來稱呼集合類的對象。,對於
字符串對象內容的集合來說會按字典順序排序(升序),對於數字內容的集合排序也會按照升序排序。
排序可一份爲兩部分內容,一個是排序的規則,也就是按照什麼來進行排序,並且排成什麼樣的順序。
第二個就是排序的算法,他決定了排序的效率。
在對自定義的集合內容類型排序時,需要先定義那個類型的排序規則。
Comparable接口,這個接口中只定義了一個compareTo(Object o),方法的返回至類型是整型,如果當前對象大於參數對象就返回正數,當前對象等於參數對象是就返回0,當前對象小於參數對象時就返回負值,這樣寫就是升序排列,反之則是進行降序排列,在實現這個接口中的方法時,返回值定義方式,只有這兩種。
根據指定類型的排序規則實現了Comparable接口,那麼就可以對存有這個類型的集合進行整體排序。Comparable接口,
也叫做可比較接口。這個接口在java.lang包下。只要實現了這個接口,就是可排序的。
接下來介紹另外一種對自定義類型對象的集合整體排序的方法,也就是實現比較器接口(Comparator),這個接口中定
義了一個compare(Object o1,Object o2)方法來比較兩個對象,這個方法的返回值定義和上面介紹的那個方法是一樣。
注意:在API,幫助文檔中以上兩個方法的參數類型是T,這代表的模板類型,也就是集合中存放的內容的類型,在JDK1.4中其參數就是Object類型,模板類型的詳細內容會在最後的JDK5.0新特性中講到。
Comparator接口可以在匿名內部類中實現,Collections 中的sort(集合了的對象,比較器)方法,可以對自定義類型內
容的集合進行整體排序。
2> LinkedList,它是List接口的實現類,其底層是用雙向循環鏈表來實現的。
注意:ArrayList的查詢效率比較高,增刪動作的效率比較差,適用於查詢比較頻繁,增刪動作較少的元素管理的集合。
LinkedList的查詢效率低,但是增刪效率很高。適用於增刪動作的比較頻繁,查詢次數較少的元素管理集合。
ArrayList,LinkedList都是線程不安全的。
實現堆棧 1,數組(ArrayList,增刪效率比較低,不適合)
2,LinkedList(實現堆棧的好方法)
3,java.util.Stack類,Stack是Vector的子類,Vector類是一個線程安全的(是一個重量級的類),並繼承
了Vector的方法,Verctor類和ArrayList的功能近乎相同。(不推薦使用Stack類來實現堆棧)。
Set接口的實現類
HashSet
Set的實現類的集合對象中不能夠有重複元素,HashSet也一樣他是使用了一種標識來確定元素的不重複,HashSet用一種算法來保證HashSet中的元素是不重複的,HashSet的底層實現還是數組。
Object類中的hashCode()的方法是所有子類都會繼承這個方法,這個方法會用Hash算法算出一個Hash(哈希)碼值返回
,HashSet會用Hash碼值去和數組長度取模,模(這個模就是對象要存放在數組中的位置)相同時纔會判斷數組中的元素和要加入的對象的內容是否相同,如果不同纔會添加進去。
Hash算法是一種散列算法。
注意:所以要存入HashSet的集合對象中的自定義類必須覆蓋hashCode(),equals()兩個方法,才能保證集合中元素容不
重複。在覆蓋和hashCode()方法時,要使相同對象的hashCode()方法返回相同值,覆蓋equals()方法再判斷其內容。爲
了保證效率,所以在覆蓋hashCode()方法時,也要儘量使不同對象儘量返回不同的Hash碼值。
如果數組中的元素和要加入的對象的hashCode()返回了相同的Hash值(相同對象),纔會用equals()方法來判斷兩個對象的內容是否相同。
SortedSet接口是Set的子接口。
TreeSet是SortedSet接口的實現類,他可以對集合中的元素進行排序。
要存放在TreeSet中自定義類的對象,這個類要麼是已經實現了Comparable接口,要麼是能給出Comparator比較器,TreeSet可以自動過濾掉重複元素所以不用重載hashCode()方法,TreeSet會根據比較規則判斷元素內容是否相同,TreeSet會在元素存入世就進行了排序。(在TreeSet給出排序規則時,一定要注意對象內容相等的條件,一定要注意在主觀的認爲兩個對象內容相同時,纔可以使用比較少的條件來進行判斷)
在要排序時才使用TreeSet類(存儲效率比較低),HashSet的存儲效率比較高,在需要爲HashSet的對象排序時,就可以把HashSet中的元素放入TreeSet。
========================
代碼:
--------------------------------------------------------------------------------
1. Exception 應用
----------------
public class TestLoginException {
public static void main(String[] args) {
UserManagement u=new UserManagement();
try {
System.out.println(u.login("Huxz","1234"));
} catch (UserNameException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (PasswordException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
System.out.println(u.login("Liucy","1250"));
} catch (UserNameException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (PasswordException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
System.out.println(u.login("TangLiang","1234"));
} catch (UserNameException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (PasswordException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class UserManagement{
String[] users={"Huxz","Liucy","Chenzq"};
String[] pwds={"1234","5678","1250"};
public String login(String name,String pwd) throws UserNameException,PasswordException{
for(int i=0;i<users.length;i++){
if (users[i].equals(name)){
if (pwds[i].equals(pwd)){
return "WelCome";
}
else{
throw new PasswordException("密碼錯誤!");
}
}
}
throw new UserNameException("用戶名不存在");
}
}
class UserNameException extends Exception{
public UserNameException() {
super();
}
public UserNameException(String msg) {
super(msg);
}
}
class PasswordException extends Exception{
public PasswordException() {
super();
}
public PasswordException(String arg0) {
super(arg0);
}
}
2. 斷言 應用示例
-------------
public class TestAssertion{
public static void main(String[] args){
int i=Integer.parseInt(args[0]);
assert i==1:"ABCDEFG";
System.out.println(i);
}
}
3. ArrayList 應用舉例, 結合Colletions.sort()
-------------------------
import java.util.*;
public class TestArrayList {
public static void main(String[] args) {
List l=new ArrayList();
/*
l.add("ABC");
l.add("DEF");
l.add("ABC");
l.add(1,"Liucy");
*/
/*
l.add("Liucy");
l.add("Chenzq");
l.add("Hiloo");
l.add("TangLiang");
l.add("Huxz");
*/
/*
l.add(new Integer(10));
l.add(new Integer(12));
l.add(new Integer(6));
*/
Student s1=new Student("Liucy",40);
Student s2=new Student("Chenzq",38);
Student s3=new Student("TangLiang",18);
l.add(s1);
l.add(s2);
l.add(s3);
Collections.sort(l);
/*
System.out.println(l.size());
String s=(String)l.get(1);
System.out.println(s);
*/
/*
for(int i=0;i<l.size();i++){
Object s=l.get(i);
System.out.println(s);
}
*/
print(l);
}
public static void print(Collection c){
Iterator it=c.iterator();
//System.out.println(it.getClass().getName());
while(it.hasNext()){
Object o=it.next();
System.out.println(o);
}
}
}
class Student implements Comparable{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "Student "+name+" "+age;
}
public int compareTo(Object o){
Student s=(Student)o;
return this.name.compareTo(s.name);
}
}
class Collections2{
public static void sort(List l){
for(int i=0;i<l.size()-1;i++){
for(int j=i+1;j<l.size();j++){
Object o1=l.get(i);
Object o2=l.get(j);
Comparable c1=(Comparable)o1;
Comparable c2=(Comparable)o2;
if (c1.compareTo(c2)>0){
Collections.swap(l,i,j);
}
}
}
}
}
代碼:
--------------------------------------------------------------------------------
4.LinkedList 實現堆棧
---------------------
import java.util.*;
public class TestStack {
public static void main(String[] args) {
MyStack ms=new MyStack();
ms.push("Chenzq");
ms.push("Liucy");
ms.push("BaiLu");
System.out.println(ms.pop());
System.out.println(ms.pop());
System.out.println(ms.pop());
}
}
class MyStack{
private LinkedList ll=new LinkedList();
public void push(Object o){
ll.addFirst(o);
}
public Object pop(){
return ll.removeFirst();
}
}
5. HashSet 應用
----------------
import java.util.*;
public class TestHashSet {
public static void main(String[] args) {
Set s=new HashSet();
/*
String s1=new String("Liucy");
String s2=new String("Chenzq");
String s3=new String("Hiloo");
String s4=new String("TangLiang");
String s5=new String("Huxz");
String s6=new String("Liucy");
*/
TarenaStudent s1=new TarenaStudent("Liucy",30);
TarenaStudent s2=new TarenaStudent("Chenzq",32);
TarenaStudent s3=new TarenaStudent("Hiloo",35);
TarenaStudent s4=new TarenaStudent("TangLiang",18);
TarenaStudent s5=new TarenaStudent("Huxz",16);
TarenaStudent s6=new TarenaStudent("Liucy",30);
s.add(s1);
s.add(s2);
s.add(s3);
s.add(s4);
s.add(s5);
s.add(s6);
print(s);
}
public static void print(Collection c){
Iterator it=c.iterator();
while(it.hasNext()){
Object o=it.next();
System.out.println(o);
}
}
}
-----
public class TarenaStudent implements Comparable {
String name;
int age;
public TarenaStudent(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "Student "+name+" "+age;
}
/*
public boolean equals(Object o){
System.out.println("Run Equals") ;
if (this==o) return true;
if (o==null) return false;
if (!(o instanceof TarenaStudent)) return false;
TarenaStudent ts=(TarenaStudent)o;
if (this.age==ts.age && this.name.equals(ts.name)) return true;
else return false;
}
public int hashCode(){
return age+name.hashCode();
}
*/
public int compareTo(Object o){
TarenaStudent ts=(TarenaStudent)o;
if (this.age!=ts.age) return this.age-ts.age;
else return this.name.compareTo(ts.name);
}
}
6. SortedSet 接口中的 TreeSet 類的應用
------------------
import java.util.*;
public class TestTreeSet {
public static void main(String[] args) {
SortedSet s=new TreeSet();
TarenaStudent s1=new TarenaStudent("Liucy",30);
TarenaStudent s2=new TarenaStudent("Chenzq",32);
TarenaStudent s3=new TarenaStudent("Hiloo",30);
TarenaStudent s4=new TarenaStudent("TangLiang",18);
TarenaStudent s5=new TarenaStudent("Huxz",16);
TarenaStudent s6=new TarenaStudent("Liucy",30);
s.add(s1);
s.add(s2);
s.add(s3);
s.add(s4);
s.add(s5);
s.add(s6);
print(s);
}
public static void print(Collection c){
Iterator it=c.iterator();
while(it.hasNext()){
Object o=it.next();
System.out.println(o);
}
}
}
day09
================
代碼:
--------------------------------------------------------------------------------
1. HashMap 實現Map接口
import java.util.*;
public class TestHashMap {
public static void main(String[] args) {
Map m=new TreeMap();
m.put("Unix","Hiloo");
m.put("CoreCpp","Chenzq");
/*
System.out.println(m.put("UC","Liucy"));
System.out.println(m.put("UC","Chenzq"));
System.out.println(m.size());
System.out.println(m.get("UC"));
*/
m.put("UC","Liucy");
m.put("CoreJava","TangLiang");
m.put("CoreJava","Huxz");
//m.put(null,null);
print(m);
}
public static void print(Map m){
Set keySet = m.keySet();
Iterator it=keySet.iterator();
while(it.hasNext()){
Object key=it.next();
Object value=m.get(key);
System.out.println(key+"--"+value);
}
}
}
class HashSet2{
private HashMap hm=new HashMap();
public void add(Object o){
hm.put(o,null);
}
}
2. 綜合應用舉例
--------------
題目:
Exam類 考試類
屬性: 若干學生 一張考卷
提示:學生採用ArrayList存放
Paper類 考卷類
屬性:若干試題
提示:試題採用HashMap存放,key爲String,表示題號,value爲試題對象
Student類 學生類
屬性:姓名 一張答卷 一張考卷
Question類 試題類
屬性:題號 題目描述 若干選項 正確答案 多選
提示:若干選項用ArrayList
AnswerSheet類 答卷類
屬性:每道題的答案
提示:答卷中每道題的答案用HashMap存放,key爲String,表示題號,value爲學生的答案
問題:爲Exam類添加一個方法,用來爲所有學生判卷,並打印成績排名(名次、姓名)
代碼:
--------------------------------------------------------------------------------
編程實現:
import java.util.*;
public class TestExam {
public static void main(String[] args) {
Exam exam=new Exam();
Paper paper=new Paper();
exam.paper=paper;
Student.paper=paper;
Question q1=new Question();
q1.questionId="Q01";
q1.answers.add("A");
q1.answers.add("B");
Question q2=new Question();
q2.questionId="Q02";
q2.answers.add("A");
q2.answers.add("B");
q2.answers.add("C");
Question q3=new Question();
q3.questionId="Q03";
q3.answers.add("B");
paper.questions.put(q1.questionId,q1);
paper.questions.put(q2.questionId,q2);
paper.questions.put(q3.questionId,q3);
Student s1=new Student();
s1.name="Liucy";
Set s=new HashSet();
s.add("A");
s.add("B");
s1.as.myAnswers.put(q1.questionId,s);
s=new HashSet();
s.add("A");
s.add("B");
s.add("C");
s1.as.myAnswers.put(q2.questionId,s);
s=new HashSet();
s.add("A");
s.add("B");
s1.as.myAnswers.put(q3.questionId,s);
exam.students.add(s1);
Student s2=new Student();
s2.name="Chenzq";
s=new HashSet();
s.add("A");
s.add("B");
s.add("C");
s2.as.myAnswers.put(q1.questionId,s);
s=new HashSet();
s.add("A");
s.add("B");
s2.as.myAnswers.put(q2.questionId,s);
s=new HashSet();
s.add("B");
s2.as.myAnswers.put(q3.questionId,s);
exam.students.add(s2);
Student s3=new Student();
s3.name="Huxz";
s=new HashSet();
s.add("A");
s.add("B");
s3.as.myAnswers.put(q1.questionId,s);
s=new HashSet();
s.add("A");
s.add("B");
s.add("C");
s3.as.myAnswers.put(q2.questionId,s);
s=new HashSet();
s.add("B");
s3.as.myAnswers.put(q3.questionId,s);
exam.students.add(s3);
exam.print();
}
}
class Exam{
Paper paper;
//element:Student
List students=new ArrayList();
public void print(){
Collections.sort(students);
int i=1;
Iterator it=students.iterator();
while(it.hasNext()){
Student s=(Student)(it.next());
System.out.println(i+":/t"+s);
i++;
}
}
}
class Paper{
//key:questionID value:Question
Map questions=new HashMap();
}
class Question{
String questionId;
String desc;
//element:String
List chooses=new ArrayList();
//element:String such as "A" "B"
Set answers=new HashSet();
}
class Student implements Comparable{
String name;
AnswerSheet as=new AnswerSheet();
static Paper paper;
public int compareTo(Object o){
Student s=(Student)o;
if (this.getMark()<s.getMark()) return 1;
else if (this.getMark()>s.getMark()) return -1;
else return name.compareTo(s.name);
}
//得到學生成績 判卷子
public double getMark(){
double c=0;
Map questions=paper.questions;
//所有的題號
Set qIds=questions.keySet();
Iterator it=qIds.iterator();
while(it.hasNext()){
String qId=(String)it.next();
Question q=(Question)questions.get(qId);
Set cAnswers=q.answers;
Set myAnswers=(Set)as.myAnswers.get(qId);
if (isSetEquals(cAnswers,myAnswers)){
c++;
}
}
return c/qIds.size()*100;
}
//判斷兩個Set是否相等
private boolean isSetEquals(Set s1,Set s2){
if (s1.size()!=s2.size()) return false;
Iterator it=s1.iterator();
while(it.hasNext()){
Object o=it.next();
if (!(s2.contains(o))) return false;
}
return true;
}
public String toString(){
return name+" "+getMark();
}
}
class AnswerSheet{
//key:String questionID
//value:Set
Map myAnswers=new HashMap();
}