#
異常機制綜述
在運行過程中,應用程序可能遭遇各種嚴重程度不同的問題.異常提供了一種在不弄亂程序的情況下檢查錯誤的巧妙方式.它也提供了一種直接報告錯誤的機制,而不必檢查標志或者具有此作用的域.異常把方法能夠報告的錯誤作為方法約定的一個顯式部分.
異常能夠被程序員看到,由編譯器檢查,并且由重載方法的子類保留.
如果遇到意外的錯誤將拋出異常,然后異常被方法調用棧上的子句捕獲.如果異常未被捕獲,將導致執行線程的終止.
異常的體系結構
毫無疑問,在java中異常是對象,它必定繼承Throwable及其子類.Throwable中含有一個用于描述異常的字符串.Exception是Throwable的一個最常用子類,另一個子類是Error.而RuntimeException繼承自Exception.

異常的種類
非檢查型異常(Unchecked Exception):
非檢查型異常反映了程序中的邏輯錯誤,不能從運行中合理恢復.
標準的運行時異常和錯誤構成非檢查型異常,它們繼承自RuntimeException和Error.
非檢查型異常不用顯示進行捕獲.
檢查型異常(Checked Exception):
這種異常描述了這種情況,雖然是異常的,但被認為是可以合理發生的,如果這種異常真的發生了,必須調用某種方法處理.
Java異常大多是檢查型異常,繼承自Exception類,你自己定義的異常必須是繼承Exception的檢查型異常.
檢查型異常必須進行顯示捕獲.
自定義異常
繼承Exception即可定義自己的異常,以下是一種常見寫法
public class DBXmlFileReadException extends Exception{
public DBXmlFileReadException(String msg){
super(msg);
}
}
拋出異常
在Java語句中,可以用throw語句拋出異常,如throw new NoSuchElementException();
拋出的對象必須是Throwable類的子類型.
拋出異常的策略:
1) 如果拋出后不可能得到處理,可以拋出Error.
2) 如果你想讓其它類自由選擇是否處理這個異常,就可以拋出RuntimeException.
3) 如果你要求類的用戶必須處理這個異常,則可以拋出Exception.
異常拋出后的控制權轉移
一旦發生異常,異常發生點后的動作將不會發生.此后將要發生的操作不是在catch塊和finally塊.
當異常拋出時,導致異常發生的語句和表達式就被稱為突然完成.語句的突然完成將導致調用鏈逐漸展開,直到該異常被捕獲.
如果該異常沒有捕獲,執行線程將中止.
Try,catch和finally
異常由包含在try塊中的語句捕獲:
try{
正常執行語句
}
catch(XException e){
異常執行語句一
}
catch(XXException e){
異常執行語句二
}
catch(XXXException e){
異常執行語句三
}
finally{
中止語句
}
Try中的語句體要么順利完成,要么執行到拋出異常.
如果拋出異常,就要找出對應于異常類或其父類的catch子句,如果未能找到合適的catch子句,異常就從try語句中擴散出來,進入到外層可能對它進行處理的try語句.
Catch子句可以有多個,只要這些子句捕獲的異常類型不同.
如果在try中有finally子句,其代碼在try把所有其它處理完成之后執行.
無論是正常完成或是出現異常,甚至是通過return或者break這樣的控制語句結束,finally子句總是被執行.
Catch子句和finally子句在try語句之后至少有一個,不要求全部出現.
More…
在catch語句中捕獲通用的異常Exception通常不是最佳策略,因為它會將所有異常進行等同處理.
不能把基類異常的catch語句放到子類異常的catch語句之前,編譯器會在運行之前就檢查出這樣的錯誤.
Try…catch對每個catch語句都從頭到尾檢查,如果找到處理同類異常的catch子句,此catch塊中的語句將得以執行,而不再處理同層次的其它catch塊.
如果catch或finally拋出另一個異常,程序將不會再去檢查try的catch子句.
Try...catch語句可以嵌套,內層拋出的異??杀煌鈱犹幚?
Throws子句
函數能拋出的檢查型異常用throws聲明,它后面可以是帶用逗號隔開的一系列異常類型.僅僅那些在方法中不被捕獲的異常必須列出.
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject();
// Read in size
int size = s.readInt();
// Initialize header
header = new Entry<E>(null, null, null);
header.next = header.previous = header;
// Read in all elements in the proper order.
for (int i=0; i<size; i++)
addBefore((E)s.readObject(), header);
}
}
More…
Throws子句的約定是嚴格強制性的,只能拋出throws子句中聲明的異常類型,拋出其它類型的異常是非法的,不管是直接利用throw,還是調用別的方法間接的拋出.
RuntimeException和Error是僅有的不必由throws子句列出的異常.
調用函數的函數要么處理對聲明的異常進行處理,要么也聲明同樣的異常,將收到的異常拋向上層.
對檢查型異常通常進行的幾種處理
1) 用e.printStackTrace()輸出異常信息.
2) 將異常記錄到日志中以備查,如logger.error(e.getMessage()).
3) 試圖進行異?;謴?
4) 告知維護者和用戶發生的情況.
內部類的出現
當進行Java開發時,有時需要實現一個僅包含1-2個方法的接口.在AWT和Swing開發中經常出現這種情況,例如當一個display組件需要一個事件回調方法如一個按鈕的ActionListener時. 如果使用普通的類來實現此操作,最終會得到很多僅在單個位置上使用的小型類.
內部類用于處理這種情況,java允許定義內部類,而且可在Gui外使用內部類.
內部類的定義和實現
內部類是指在另一個類內部定義的一個類.可以將內部類定義為一個類的成員.
public class Linker{
public class LinkedNode{
private LinkedNode prev;
private LinkedNode next;
private String content;
public LinkedNode(String content){
this.content=content;
}
}
public Linker(){
LinkedNode first=new LinkedNode("First");
LinkedNode second=new LinkedNode("Second");
first.next=second;
second.prev=first;
}
}
定義在一個類方法中的內部類
public class Hapiness{
interface Smiler{
public void smile();
}
public static void main(String[] args){
class Happy implements Smiler{
public void smile(){
System.out.println(":-}");
}
}
Happy happy=new Happy();
happy.smile();
}
}
匿名類
對很多情況而言,定義在方法內部的類名意義不大,它可以保持為匿名的,程序員關心的只是它的實例名.
如:
Runnable runner=new Runnable(){
public void run(){
// Run statememnt
}
}
理解匿名類
匿名類并不難理解,它只是把類的定義過程和實例的創建過程混合而已,上頁的語句實際上相當于如下語句:
// 定義類
Public class Runner implements Runnable{
public void run(){
// do sth
}
}
// 創建實例
Runner runner=new Runner();
使用匿名類的篩選解耦過程
需求:從公司的職員列表中,找出男性且年齡大于22的成員.
傳統寫法:
List allmembers=company.getMembers();// 取得所有成員
List results=new ArrayList();// 結果列表
for(Iterator it=allmembers.iterator();it.hasNext();){
Member member=(Member)it.next();
if(member.getAge()>22 && member.isMale()){ // 篩選,這里是把查詢條件和遴選過程融合在一起,條件一變立即就得加個分支.
results.add(member);
}
}
傳統方法的缺陷
這種寫法沒有錯,但是不是面向對象的寫法,它有以下缺陷:
1.查詢條件和篩選過程沒有分離.
2.這樣寫的后果使Company變成了一個失血模型而不是領域模型.
3.換查詢條件的話,上面除了"篩選"一句有變化外其它都是模板代碼,重復性很高.
使用匿名類實現的OO化查詢
真正符合OO的查詢應該是這樣:
MemberFilter filter1=new MemberFilter(){
public boolean accept(Member member) {
return member.isMale() && member.getAge()>22;
}
};
List ls=company.listMembers(filter1);
這段代碼成功的把查詢條件作為一個接口分離了出去,接口代碼如下:
public interface MemberFilter{
public boolean accept(Member member);
}
查詢函數的變化
而類Company增加了這樣一個函數:
public List searchMembers(MemberFilter memberFilter){
List retval=new ArrayList();
for(Iterator it=members.iterator();it.hasNext();){
Member member=(Member)it.next();
if(memberFilter.accept(member)){
retval.add(member);
}
}
return retval;
}
這就把模板代碼歸結到了類內部,外面不會重復書寫了.Company也同時擁有了數據和行為,而不是原來的數據容器了.
匿名類的例子二
用匿名類處理分類匯總的方法 分類匯總是統計中常用,舉例來說如統計學生成績,及格不及格的歸類,分優良中差等級歸類等,每個單項代碼很好寫,但是如果分類匯總的項目多了,能一種匯總寫一個函數嗎? 比如說有些科目60分才算及格,有些科目50分就算;有些老師喜歡分優良中差四等,有些老師卻喜歡分ABCD;不一而足,如果每個都寫一個函數無疑是個編寫和維護惡夢. 如果我們用匿名類把分類匯總的規則和分類匯總的過程分別抽象出來,代碼就清晰靈活多了,以下代碼講述了這個過程.
基本類Student
public class Student{
private String name;
private int score;
public Student(String name,int score){
this.name=name;
this.score=score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
用于分類匯總的類
它強制子類實現getKey和getvalue兩個方法:
public abstract class ClassifyRule {
public Student student;
public ClassifyRule(){
}
public void setStudent(Student student) {
this.student = student;
}
abstract public String getKey();
abstract public int getValue();
}
對Student進行統計處理的StudentService類
注意getSum方法,它保留了篩選過程,篩選規則則不在其中:
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
public class StudentService {
private List<Student> students;
public StudentService() {
students = new ArrayList<Student>();
}
public void add(Student student) {
students.add(student);
}
public Hashtable<String, Integer> getSum(ClassifyRule rule) {
Hashtable<String, Integer> ht = new Hashtable<String, Integer>();
for (Student student : students) {
rule.setStudent(student);
String key = rule.getKey();
int value = rule.getValue();
if (ht.containsKey(key)) {
Integer oldValue = ht.remove(key);
oldValue += value;
ht.put(key, oldValue);
} else {
ht.put(key, value);
}
}
return ht;
}
}
測試代碼,注意其中篩選規則的創建
public class Test {
public static void main(String[] args) {
// 初始化
StudentService service = new StudentService();
service.add(new Student("Andy", 90));
service.add(new Student("Bill", 95));
service.add(new Student("Cindy", 70));
service.add(new Student("Dural", 85));
service.add(new Student("Edin", 60));
service.add(new Student("Felix", 55));
service.add(new Student("Green", 15));
// 60分及格篩選
ClassifyRule rule60 = new ClassifyRule() {
public String getKey() {
return student.getScore() >= 60 ? "及格" : "不及格";
}
public int getValue() {
return 1;
}
};
System.out.println("60分及格篩選");
printHt(service.getSum(rule60));
// 50分及格篩選
ClassifyRule rule50 = new ClassifyRule() {
public String getKey() {
return student.getScore() >= 50 ? "及格" : "不及格";
}
public int getValue() {
return 1;
}
};
System.out.println("\n50分及格篩選");
printHt(service.getSum(rule50));
// 分"優良中差"等級
ClassifyRule ruleCn = new ClassifyRule() {
public String getKey() {
String retval = "";
int score = student.getScore();
if (score >= 90) {
retval = "優";
} else if (score >= 80) {
retval = "良";
} else if (score >= 60) {
retval = "中";
} else if (score > 0) {
retval = "差";
}
return retval;
}
public int getValue() {
return 1;
}
};
測試代碼
System.out.println("\n分優良中差等級篩選");
printHt(service.getSum(ruleCn));
// 分"ABCD"等級
ClassifyRule ruleWest = new ClassifyRule() {
public String getKey() {
String retval = "";
int score = student.getScore();
if (score >= 90) {
retval = "A";
} else if (score >= 80) {
retval = "B";
} else if (score >= 60) {
retval = "C";
} else if (score > 0) {
retval = "D";
}
return retval;
}
public int getValue() {
return 1;
}
};
System.out.println("\n分ABCD等級篩選");
printHt(service.getSum(ruleWest));
}
private static void printHt(Hashtable ht) {
for (Iterator it = ht.keySet().iterator(); it.hasNext();) {
String key = (String) it.next();
Integer value = (Integer) ht.get(key);
System.out.println("Key=" + key + " Value=" + value);
}
}
}
測試結果如下:
60分及格篩選
Key=及格 Value=5
Key=不及格 Value=2
50分及格篩選
Key=及格 Value=6
Key=不及格 Value=1
分優良中差等級篩選
Key=優 Value=2
Key=良 Value=1
Key=中 Value=2
Key=差 Value=2
分ABCD等級篩選
Key=A Value=2
Key=D Value=2
Key=C Value=2
Key=B Value=1
小結
內部類也叫嵌套類,一般不提倡書寫,但它在java核心類中都存在,如接口Map中的Entry,我們應該了解并能解讀這種方法.
匿名類相對而言有用得多,在解耦合和事件回調注冊中很常見,大家應該對它的運用融會貫通.
Abstract class:抽象類
Abstract method:抽象方法
Annotation:注釋
Anonymous class:匿名類
API(Application Programming Interface):應用編程接口,由方法和語言構成的庫.
ArrayList:實現了List接口的動態數組
Assertion:斷言
Atrribute map:屬性映射
Autoboxing:自動裝箱,表示一個內置類型如int和它的包裝類如Integer之間的自動轉換
Boolean function:布爾函數
Bytecode:字節碼
Casting:類型強制轉換
Channel:頻道
ClassCastException:當一個對象引用強制轉換程一個不兼容的類型時出現的異常.
Collection:一個表示對象組或集合的接口
CSV(Comma-separated values):一種用于存儲表格數據的文件形式
Complier:編譯器
Compose:合成
Composite function:復合函數,通過多個函數創建的一個函數
Decimal:十進制
Deep:深度
DOM(Document Object Model):文檔對象模型,一種采用樹形表示來處理XML數據的API.
Database:數據庫
Edge:邊
Element:元素,XML文檔中的一個節點.
Encapsulation:封裝
End tag:結束標簽
Enum:枚舉
Escaping:轉義
Function:函數
Fuzzy search:模糊搜索
Generic:泛型
Graph:圖
GUI:用戶圖形界面
Grid computing:網格計算
Group:組
HashMap:一個將鍵值映射到值的查找對象
Heap memory:堆內存
HTML(Hyper Text Markup Language):超文本標記語言
HTTP(HyperText Tranfer Protocol):超文本傳輸協議
Inheritance:繼承
Inner class:內部類
Iterator:允許迭代到任何Collection類的一個接口
JDBC(Java Database Connectivity):java數據庫連接,一種屬于Java核心庫的用于操作關系數據庫的API.
JDK(Java Development Kit):java開發工具包
JRE(Java Runtime Environment):java運行時環境
JSP(Java Server Page):java服務頁
JVM(Java Virtual machine):Java虛擬機
JavaDoc:屬于JDK的一種文檔生成工具
JavaScript:運行于客戶端,用于HTML處理的一種輕量級教本語言,語法部分類似于Java.
Layout:布局
Lexical analysis:詞法分析
Linked List:鏈表
Matcher:一個用于正則表達式模式匹配的Java類
Metadata:元數據
Millisecond:微妙
Namespace:命名空間
Neural network:神經網絡
Node:節點
Object-oriented programmming:面向對象編程
Object pool:可以從中獲得對象的一個實例池
Origin:原點
Override:子類覆寫父類的方法
Parser:分析器
Patch:補丁
Pattern:模式
Polymorphism:多態性
Port:端口
Predicate:謂詞
Prefix:前綴
Procedural language:過程式語言,如C
Property:屬性
Real time:實時
Recursive:遞歸
Reference:引用
Reflection:反射
Regular expression:正則表達式
Relative:相對
Resource:資源
Runnable:多線程編程使用的一個接口.
Syntax:語法
Screen scraping:屏幕抓取
Split:分割
State:狀態
Static:靜態
Sequence:序列
Swing:構建在AWT上更高級的圖形用戶界面
Synchronized:同步,用于線程安全協作的技術
Tag:標簽
Thread:進程
Tiger : Sun給Java1.5的代號
Token:標記
Translation:平移
Triple:三元組
Type:類型
Unicode:統一字符界面
Unit testing:單元測試
Visitor pattern:訪問者模式
WAR(Web Application Archive):Web應用程序歸檔
Web Service:Web服務
Weight:權
Well-formed:格式良好的
Whitespace:空白符
XML(Extensible Markup Language):一種描述分級數據結構的文本標記語言
編寫程序前的設計與思考
1.分析業務,從業務流和業務規則中歸納出領域對象.這些對象一般放在src/com/yourname/domain下.
2.根據業務,考慮為領域對象提供完整的服務需要那些服務類.這些對象一般放在src/com/yourname/service下.
3.思考從輸入開始,到輸出結束,程序要運行正常,服務類需要那些屬性和方法,這些成員代表什么意義具有什么價值,方法的參數的返回值分別是什么.
4.思考要讓服務類為領域對象類提供完整普適的服務,領域對象類需要做怎樣的調整,需要歸納那些共同的基類.這里可以繪出領域類和服務類的靜態類圖協助思考.
5.考慮還需要那些實用類來幫助實現程序.這些對象一般放在src/com/yourname/util下.
6.在領域類和服務類的基礎上設計持久層,控制層和表現層(當前階段暫時不會接觸).
軟件設計的通用原則
Domain first:先歸納程序的領域對象,歸納出來才清楚程序要做什么.
Service second:其次歸納程序的服務對象,歸納出來才知道該怎么去做.
前兩步完成后可以說設計已經完成了大半.
Persistence the third:再次再考慮數據如何持久化到持久層中,比如說數據庫表結構的設計.
Presentation the last:最后考慮表現層的東西,比如說界面方案.
現代軟件設計的核心-類的設計
從上兩步可以看出,軟件設計其實就是類的設計工作,類設計的結果直接影響著軟件的方方面面,所謂持久層設計,表現層設計都是類設計的泛化和深化,所以說類設計直接影響著軟件的興衰成敗.
那么關于類設計的準則和評價標準是什么呢?
類設計的五條基本準則
單一職責原則(The single responsibility principle): 一個類有且只有一個中心目的,它為一個中心目的所設計,只能因為中心目的相關原因而改變.
開放-封閉原則(The open-close principle):類高度內聚,和其它類的耦合程度小,應該可以在不改變類的情況下,改變類所在的環境.
里斯科夫替換原則(The Liskov substitution principle):派生類的行為為基類所規定和限制,避免使派生類的方法非法化或者退化它們.基類的使用者不需要了解派生類就能正確的通過接口使用它們.
依賴關系倒置原則(The dependecy inversion principle):基于抽象類和接口而不是具體的類形成設計構架,因為抽象類和接口相對具體類而言更不容易被改動.
接口隔離原則(The interface segregation principle):給對象的每個使用者一個單獨的接口.其中只包含它們需要的方法,不要設計一個包含很多方法的接口讓不需要這些接口的類去實現它們.
類的評價標準-抽象相關
類是否有一個中心目的.
類的命名是否恰當,其名字是否表現了其中心目的.
類的接口是否展現了一致的抽象.
類的接口是否讓人明白的知道該如何使用它.
類的接口是否足夠抽象,是你能不必顧慮它是如何進行服務的.
類提供的服務是否足夠完整,能讓其它類無須了解動用其內部結構.
是否已經去除無關信息.
是否考慮過把類進一步分解成組件類?是否已經盡可能將其分解.
再修改類時是否維持了其接口的完整性.
類的評價標準--封裝相關
是否把類成員的可訪問性降至最小.
是否避免暴露類中的數據成員.
類是否已經盡可能的對其它類隱藏了實現細節.
類是否避免對其使用者,包括其派生類如何使用它做了假設.
類是否不依賴其它類,它是松耦合的嗎?
典型的設計的臭味
僵化性(Rigidiry):類之間耦合嚴重,系統幾乎很難改變,改變一處就不得不改動其它地方,甚至引起無休止的連鎖反應.
易碎性(Fragility):改變系統的某個部分,會破壞許多完全無關的部分.這一般由不必要的語法結構引起,如過度復雜的循環和分支.
固化性(Immobility):很難將系統分解成可供其它系統使用的組件,細化不夠會引起這樣的問題.
粘稠性(Viscosity):開發環境總是和輸入輸出和庫粘在一起.永遠走不出編輯->編譯->測試這一無休止的循環,分層不清晰會引起這樣的問題.
不必要的復雜性(Needless Complexity):很多充滿著智慧的代碼結構目前還不需要,但有一天可能會排上用場,喜歡事先考慮幽靈需求的程序員經常給代碼帶來這樣的異味.
不必要的重復(Needless Repetition): 系統充斥著重復代碼,看上去象只會VC大法(Ctrl+C,Ctrl+V)的程序員寫的,懶惰不思考是造成這個問題的根源.
不透明性(Opacity):代碼不能體現創建人的意圖.
何謂良好的設計
設計良好的系統應該容易理解,容易改變,容易重用.它實現起來沒有任何特殊的困難,簡明扼要而經濟.它不會散發出代碼臭味,公司樂于生產這樣的系統,客戶樂于使用這樣的系統,維護人員樂于維護這樣的系統.
設計良好的現代軟件特征
最小的復雜度:整個系統可以分解為簡單而易于理解的各個部分.
易于維護:程序有良好的可維護性.
松散耦合,通過應用類接口中的合理抽象,封裝性以及信息隱藏等原則,設計出相互關聯盡可能最少的類.
適應變化: 能在不改變系統基本構架的基礎上,適應未來的變化,有良好的擴展性,程序可擴展,可重用.
有明晰的層次,每層各司其職,有良好分工.
高扇入低扇出:系統很好的利用了較低層次上的工具類,重復代碼很少或沒有.
有良好的規范:無論多少人參與了項目,從代碼看來猶如出自一人之手.
使用標準技術.
集合框架的繼承體系
Java2中包含了6個集合接口,這些接口的通用目的實現類,以及一個集合實用類Collections,共同組成了集合框架的核心.
6個集合接口如下:
Collection及其以下的List,Set,以及Set下的SortedSet
Map及其以下的SortedMap
鏈表的通用實現
ArrayList:線程不安全的動態數組類,批量查詢速度快,單個查找速度慢.
Vector:線程安全的動態數組類,效率比ArrayList低下.
LinkedList:動態鏈表類,適于在隊列首尾頻繁增刪成員的場合.
鏈表的創建
List<Member> ls=new ArrayList<Member>();// 1.5版本及以上
List ls=new ArrayList();// 1.5版本以下
之所以將ls類型指定為List<Member>而不是ArrayList<Member>是因為 如果情況變化, ArrayList需要修改成Vector或LinkedList時無須修改其它代碼,僅修改實例類型即可.
向List中添加元素
添加單個元素
ls.add(new Member("Andy",21));
從別的鏈表中添加多個元素
List<Member> ls2=new ArrayList<Member>();
ls2.add(new Member("Felex",21));
ls2.add(new Member("Gates",23));
ls.addAll(ls2);
注意:
1.5及其以上版本中,添加的元素必須和定義時一致,如ls的類型是List<Member>,那么向其中添加的元素必須是Member或其子類.
1.5以下版本中,對添加的元素不作檢查,只要是Object即可,如果是基本類型則需裝箱成類類型.如ls.add(new Integer(8));
刪除鏈表中元素
ls.remove(member); // 直接刪除對象,member=new Member("Edin",28)
ls.remove(2); // 刪除第三個元素
ls.clear(); // 將已有數據全部清除
對鏈表進行遍歷
1) 1.5中獨有的遍歷方法,代碼最短,使用最方便
for(Member member:ls){
// member就是依次取出的每個元素
}
2) 常規方法,多用于需要取得下標的場合,各版本均適用
for(int i=0;i<ls.size();i++){
Member member=ls.get(i);// member就是依次取出的每個元素, 1.5及其以上版本適用, ls.size()為鏈表長度
Member member=(Member)ls.get(i);// 1.5以下版本適用
}
3) 使用Iterator對鏈表進行遍歷的方法,各版本均適用
for(Iterator it=ls.iterator();it.hasNext();){
Member member=(Member)it.next();
}
鏈表的其它常用的方法
ls.contains(Object o);// 返回鏈表中是否包含某元素
ls.indexOf(Object o);// 返回對象o是鏈表中的第幾號元素
isEmpty();// 返回鏈表中是否有元素
對鏈表進行排序
1)讓List中元素必須已經實現Comparable接口:
public class Member implements Comparable {
private String name;
private int age;
public Member(String name, int age) {
this.name = name;
this.age = age;
}
public int compareTo(Object obj) {
Member another = (Member) obj;
return this.name.compareTo(another.name);// 按名稱排序,如果是this.age-another.age則按年齡排序
}
public String toString(){
return "Member name="+name+" age="+age;
}
}
2)排序過程
List<Member> ls=new ArrayList<Member>();
ls.add(new Member("Felex",21));
ls.add(new Member("Gates",23));
ls.add(new Member("Andy",21));
ls.add(new Member("Bill",23));
ls.add(new Member("Cindy",24));
ls.add(new Member("Dell",27));
Collections.sort(ls);
for(Member member:ls){
System.out.println(member);
}
輸出:
Member name=Andy age=21
Member name=Bill age=23
Member name=Cindy age=24
Member name=Dell age=27
Member name=Felex age=21
Member name=Gates age=23
// 如果需要逆序可以使用Collections.reverse(ls);
鏈表與數組之間的轉換
1) List轉換成數組
List<String> ls=new ArrayList<String>();
ls.add("Felex");
ls.add("Gates");
ls.add("Andy");
ls.add("Bill");
ls.add("Cindy");
ls.add("Dell");
Object[] arr=ls.toArray();
for(Object obj:arr){
System.out.println((Object)obj);
}
輸出為:
Felex
Gates
Andy
Bill
Cindy
Dell
2) 數組轉換成List
String[] arr={"Andy","Bill","Cindy","Dell"};
List<String> ls=Arrays.asList(arr);
for(String str:ls){
System.out.println(str);
}
輸出:
Andy
Bill
Cindy
Dell
Hashtable-哈希表類
以哈希表的形式存儲數據,數據的形式是鍵值對.
特點:
查找速度快,遍歷相對慢
鍵值不能有空指針和重復數據
創建
Hashtable<Integer,String> ht=new Hashtable<Integer,String>();
添值
ht.put(1,"Andy");
ht.put(2,"Bill");
ht.put(3,"Cindy");
ht.put(4,"Dell");
ht.put(5,"Felex");
ht.put(6,"Edinburg");
ht.put(7,"Green");
取值
String str=ht.get(1);
System.out.println(str);// Andy
對鍵進行遍歷
Iterator it = ht.keySet().iterator();
while (it.hasNext()) {
Integer key = (Integer)it.next();
System.out.println(key);
}
對值進行遍歷
Iterator it = ht.values().iterator();
while (it.hasNext()) {
String value =(String) it.next();
System.out.println(value);
}
取Hashtable記錄數
Hashtable<Integer,String> ht=new Hashtable<Integer,String>();
ht.put(1,"Andy");
ht.put(2,"Bill");
ht.put(3,"Cindy");
ht.put(4,"Dell");
ht.put(5,"Felex");
ht.put(6,"Edinburg");
ht.put(7,"Green");
int i=ht.size();// 7
刪除元素
Hashtable<Integer,String> ht=new Hashtable<Integer,String>();
ht.put(1,"Andy");
ht.put(2,"Bill");
ht.put(3,"Cindy");
ht.put(4,"Dell");
ht.put(5,"Felex");
ht.put(6,"Edinburg");
ht.put(7,"Green");
ht.remove(1);
ht.remove(2);
ht.remove(3);
ht.remove(4);
System.out.println(ht.size());// 3
Iterator it = ht.values().iterator();
while (it.hasNext()) {
// Get value
String value =(String) it.next();
System.out.println(value);
}
輸出:
3
Green
Edinburg
Felex
類,抽象類與接口
類,抽象類與接口都是Java中實現繼承和多態的手段.
類強調的是繼承
接口強調的是規范
抽象類兼而有之
什么是接口
接口是一種特殊的類,它只有方法定義而沒有實現,實現的任務完全交給子類完成.
接口以interface標志.
繼承接口用implements關鍵字實現.
接口可以繼承接口.
接口可以有成員,但成員全是public static final類型的.
接口沒有構造函數.
接口給Java提供了多繼承機制
接口例子—Knockable
public interface Knockable{
public static final String Sound="Bang!";
public void knock();
}
接口例子-實現接口
public class Hammer implements Knockable{
public void knock(){
System.out.println(Sound);
}
}
接口例子-實現多個接口
public interface Knockable{
public static final String Sound="Bang!";
public void knock();
}
public interface Clampable {
public void clamp();
}
public class Pliers implements Knockable,Clampable{
public void clamp(){
// do sth
}
public void knock(){
System.out.println(Sound);
}
}
接口繼承接口例子
public interface Knockable{
public static final String Sound="Bang!";
public void knock();
}
public interface Hitable extends Knockable{
public void hit();
}
public class Stick implements Hitable{
public void knock(){
// do sth
}
public void hit(){
// do sth
}
}
什么叫抽象類
類中具有抽象方法的類為抽象類.抽象方法以abstract在函數前修飾,只有定義沒有實現,這一點和接口一致.
抽象類在類名前需加上abstract修飾符以標識.
抽象類不能生成實例.
抽象類的繼承性和類一致.
抽象類的實現
public abstract class Gun{
protected String cannon;
protected List<Bullet> bullets;
public abstract void shoot();
public void addBullet(Bullet bullet){
if(bullets==null){
bullets=new LinkedList<Bullet>();
}
bullets.add(bullet);
}
}
繼承抽象類
public class Rifle extends Gun{
public void shoot(){
// Shoot Sth
}
public void reload(){
if(bullets!=null){
bullets.clear();
}
addBullet(new Bullet());
addBullet(new Bullet());
addBullet(new Bullet());
addBullet(new Bullet());
addBullet(new Bullet());
addBullet(new Bullet());
}
}
繼承抽象類并實現接口
public abstract class Gun{
protected String cannon;
protected List<Bullet> bullets;
public abstract void shoot();
public void addBullet(Bullet bullet){
if(bullets==null){
bullets=new LinkedList<Bullet>();
}
bullets.add(bullet);
}
}
public interface Thornable{
public void thorn();
}
public class SpringFieldRifle extends Gun implements Thornable{
public void thorn(){
// thorn sth
}
public void shoot(){
// shoot sth
}
}
抽象類繼承抽象類實現接口的例子
public abstract class Gun{
protected String cannon;
protected List<Bullet> bullets;
public abstract void shoot();
public void addBullet(Bullet bullet){
if(bullets==null){
bullets=new LinkedList<Bullet>();
}
bullets.add(bullet);
}
}
public interface Handable{
public void hold();
}
public abstract class HandGun extends Gun implements Handable{
}
public class BlackStar extends HandGun{
public void hold(){
// Hold the gun
}
public void shoot(){
// Shoot Sth
}
}
抽象類,接口,類的區別
繼承好比家學淵源,所謂"忠厚傳家久,詩書繼世長",家長總會潛移默化的影響下一代,下一代也會在不經意中學習前輩的特點,但因為年少分辨能力不高加上世易時移有些優點已經不再是有點甚至會變成缺點,下一代會把前輩的優缺點不分良莠的繼承下來.這也是日后出現問題的根源.
接口好比拜師學藝,"入了這個門,就得說這行話",比如相聲界說學逗唱四門是必須要學的,但是"師傅領進門,修行在個人",學得怎么樣還全看自己,指望不費力的繼承什么是不可能的,具體功夫還得個人來過. 因為是自己來,具體實現成什么樣自由度也很大,比如四門功課中的"唱",原指唱太平歌詞,但因為愛聽的少,現在相聲演員已經不要求這個了,改為唱歌唱戲的唱,其實嚴格界定的話是"學"的一種.這也無所謂對錯,郭德剛堅持唱太平歌詞也行,笑林唱流行歌曲也不錯,總之實現了就可以,實現得怎么樣則留給實踐來檢驗.一個類可以同時實現多個接口,就和藝人拜幾個師傅是沒有問題的,郭德剛就同時實現了大鼓和相聲兩個接口.
抽象類則介于繼承和接口之間,既可不費力的從上一代繼承,也可強制實現某接口,有如某大師收自己的孩子為徒,當然相聲界不讓這么干,其它曲藝行業還是可以的,比如京劇界的梅蘭芳和其子梅葆玖,既有言傳身教,也有強制實現,綜合了繼承和接口的特點.
抽象類,接口,類的詳細區別
|
接口 |
抽象類 |
類 |
可以繼承自 |
接口 |
抽象類,類 |
抽象類,類 |
可以實現自 |
無 |
一個或多個接口 |
一個或多個接口 |
有否成員 |
只有static final成員 |
均可 |
均可 |
是否有構造函數 |
無 |
有 |
有 |
可否實例化 |
不可 |
不可 |
可 |
意圖 |
規范行為 |
繼承成員+規范行為 |
繼承成員 |
抽象類,接口和類在繼承體系中的位置
抽象類,接口一般來說都是從一般類總結歸納出來的抽象共性的東西,類則是實際具體的東西.
一般來說,應該把合理抽象出的抽象類,接口放在類繼承體系的上層,子類依靠類來實現.