1. 程式人生 > >類與類之間的關係與匿名內部類的使用,異常的處理

類與類之間的關係與匿名內部類的使用,異常的處理

  1. final關鍵字
    修飾類, 表示最終類,不能被繼承
    修飾成員變數(欄位), 一般與static同時使用, 稱為final常量 ,在定義時必須初始化,不能修改
    修飾方法, 不能被重寫
    修飾區域性變數, 一旦初始化後就不能再修改. 注意,如果修飾的是引用型別變數,這個引用不能再指向其他物件,可以修改它的屬性值
    修飾形參,在方法體中不能再重新賦值

  2. 抽象類
    為什麼使用抽象方法?
    類的某個功能(行為,操作)不能具體實現,每個子類都有自己的實現方式,這個操作就可以定義為抽象方法
    抽象類的特點:

  1. 使用abstract修飾的類為抽象類
  2. 含有抽象方法的類必須定義為抽象類, 抽象類中不一定含有抽象方法
  3. 抽象類不能例項化物件, 抽象類的引用需要賦值子類物件, 但是抽象類中肯定含有構造方法, 子類建立物件時先呼叫父類的構造方法再執行子類的構造方法
  4. 抽象類一般作為父類存在,子類繼承了的抽象類,需要重寫抽象類的抽象方法, 如果沒有重寫所有的抽象方法,子類也需要定義為抽象類
  5. abstract與final不能同時使用
  1. 介面
    定義:
    interface 介面名 {
    方法預設使用public abstract修飾
    可以定義public static靜態方法
    可以定義public default方法, 該方法有預設的方法體, 實現類可以重寫,也可以重寫
    欄位預設使用public static final修飾
    }

    使用:
    	class  類名   implements  介面名{
    

    重寫介面中的抽象方法
    }

    介面的特點:
    
  1. 類實現了介面,需要重寫介面中所有的抽象方法, 如果沒有重寫所有抽象方法,類需要定義為抽象類
  2. 介面支援多繼承
  3. 介面支援多實現, 一個類在繼承父類的同時,可以實現多個介面,需要重寫所有介面的抽象方法
  4. 介面是引用資料型別,可以定義變數,不能例項化物件, 介面的引用需要賦值實現類物件, 通過介面的引用呼叫抽象方法時, 實際上執行的是實現類物件的方法, 介面多型.
  5. 介面的內容
    抽象類與介面的異同點:
    相同點:
    都 可以定義抽象方法, 抽象方法需要被重寫
    不能例項化物件
    可以定義public static方法,public static final常量
    不同點:
    定義方式不同:
    內容不同: 抽象類有構造方法, 介面中有public default方法
    使用方式不同:
    應用場景不同:
    類只支援單繼承, 介面支援多繼承
    介面的應用:
    介面簡單的理解為功能的封裝
    介面某種程度上可以解決類的多繼承
    介面中可以定義一組操作規範, 標準/協議
    提倡面向介面的程式設計
    使用靈活, 一個類只能繼承一個父類, 可以同時實現多個介面
    易擴充套件, 介面作為方法的形參,呼叫方法時,可以傳遞各種實現類物件
    使專案分層

1 類與類之間的關係
泛化關係 (繼承)
子類繼承父類, 子介面繼承父介面

實現關係
	一個類實現了介面
	 
依賴
	在A類中, 使用B類作為方法的返回值型別, 引數型別,區域性變數型別, 稱A類依賴B類
	 
關聯
	在A類, 使用B類定義了成員變數, 稱A類關聯B類
	 
聚合
	聚合是關聯的一種, A類是由若干的B類組成,但是A類不能決定B類的生命週期
	 
組合
	組合是關聯的一種, A類是由若干的B類組成,並且A類可以決定B類的生命週期
	 

is a 關係,  子類 is  a 父類, 父類是通用類,子類是特殊類, 也只有當符合is a 關係時才可以使用繼承
like a 關係,  類 like a 介面, 實現關係
has a 關係,  A類  has  a   B類 , 關聯

2 內部類
在一個類的內部再定義一個類,這就是內部類
內部類包括: 成員內部類, 靜態內部類, 區域性內部類, 匿名內部類(->可以簡化匿名內部類jdk8中出現了)

1)成員內部類:
class Outer1{
int xx = 10 ; //例項變數
class Inner1 { //成員內部類
}
}
成員內部類與例項變數一樣,屬於某個外部類物件的, 先建立外部類物件,才能使用這個物件的成員內部類
成員內部類一般在Outer1外部類的例項方法中 使用

  1. 靜態內部類
    class Outer2{
    static int yy = 20 ; //靜態變數
    static class Inner2{ //靜態內部類
    }
    }
    靜態內部類跟Outer2的物件沒有關係
    一般在外部類Outer2的靜態方法中建立靜態內部類物件

  2. 區域性內部類
    class Outer3{
    public void m1(){
    int zz = 33; //區域性變數
    class Inner3{ //區域性內部類
    }
    }
    }
    區域性內部類在當前程式碼塊中,定義位置開始到包含它 的大括弧範圍內建立物件,

4)匿名內部類(掌握)
匿名內部類就是沒有類名的內部類
匿名內部類的定義與匿名內部類物件的建立必須在一起, 匿名內部類只使用一次

介面/抽象類不能例項化物件, 可以給介面/抽象類的引用賦值匿名內部類物件
當介面的實現類/抽象類的子類只使用一次時, 可以給介面/抽象類的引用賦值匿名內部類物件

注意:
所有的類編譯後都會生成獨立的位元組碼檔案, 檔名:外部類名$內部類名.class

3 異常
3.1 概述
異常就是程式執行過程中遇到的不正常現象.
之前遇到的異常有哪些?
空指標異常
算術異常
型別轉換異常

之前遇到了這些異常導致了程式的崩潰.
通過異常處理不會讓程式崩潰, 程式會繼續執行, 通過異常處理,可以提高程式的健壯性(魯棒性,robust).

Java中 對這些異常現象進行了抽象,形成了異常相關的類
Throwable是異常類的父類, 表示所有的異常都是可丟擲的.

說明:
  1. Throwable類中getMessage()獲得異常的資訊, printStackTrace()列印異常的棧跟蹤資訊, Java類繼承是可傳遞的,所有的異常都有這兩個方法
  2. 平時所說的異常指的是Exception異常, 它分為編譯時異常和執行時異常. 程式中出現的異常,有的是程式設計師完全可以避免掉的, 有的是程式設計師也無法控制的.
    如 : 之前遇到的空指標異常, 是因為物件為null,訪問物件的例項成員就會產生空指標異常, 程式設計師在訪問物件的例項成員前, 只要確保物件不為null就不會產生空指標異常. 在開發時, 可以通過if()條件判斷, 如果物件不為null就訪問它的例項成員

再如: 程式如果要訪問某個檔案, 如果要訪問的檔案不存在就會產生異常. 當程式部署到客戶的機器上後, 客戶可能因為誤操作把要訪問的檔案給刪除. 程式設計師不能控制客戶的誤操作. 因為客戶的誤操作產生的異常,我們程式設計師是沒有辦法避免的. 程式設計師能做的是,一旦產生了這些異常, 怎麼辦?? 即當這類異常發生時, 程式設計師應該提供有針對性的措施,而不至於使程式崩潰. 這種異常就是編譯時異常

		再如, 如果程式需要通過網路訪問某些資源,在訪問過程中網路中斷了,這也是程式設計師不可控的.程式設計師能做的是, 萬一出現了這種情況, 提供預防措施, 不至於程式中斷.

		有些異常是程式設計師通過規範的程式碼可以進行規避,這些異常是執行時異常;有些異常是程式設計師控制不了的,這類異常就是編譯時異常

3.2異常處理
執行時異常,不需要進行預處理, 而在通過規範的程式碼進行規避.
編譯時異常必須進行預處理,否則編譯報錯.

3.2.1 try…catch捕獲處理
try{
對可能產生異常的程式碼進行檢視
某一條語句一旦產生異常,會立即跳轉到catch子句執行, try程式碼塊後面的語句不再執行
try程式碼塊可能會有多語句有異常需要預處理, 可以通過多個catch子句分別預處理
}catch( 異常型別1 e1 ){
捕獲了異常型別1的異常, 進行預處理,
在開發階段, 一般的處理方式就是把異常資訊列印到螢幕上,方便程式設計師除錯
e1.printStackTrace();
}catch( 異常型別2 e2){
如果有多個 catch子句, 異常型別之間存在繼承關係的話, 先捕獲子異常,再捕獲父異常
或者直接捕獲父異常
}finally{
不管是否產生異常,finally子句總是會執行
一般會在finally子句中釋放系統所佔資源
}

3.2.2 throws丟擲處理

應用場景:
  1. 程式設計師在定義方法時, 如果方法體中通過throw語句丟擲了一個異常物件, 所在的方法應該通過throws宣告該異常

  2. 程式設計師在定義方法時, 如果在方法體中呼叫了其他的方法, 被呼叫的方法有受檢異常需要預處理,可以try…catch捕獲處理,也可以throws丟擲處理
    3)一般情況下 , 呼叫的方法如果有受檢異常 需要預處理時, 進行try…catch捕獲處理

    為什麼要throws把異常宣告丟擲??
    提醒方法的呼叫者, 可能會產生異常, 需要進行預處理

3.3 方法覆蓋中的異常處理
方法覆蓋(方法重寫)規則:

  1. 方法簽名必須相同, 方法名與引數列表必須一樣
  2. 返回值型別, 子類方法的返回值型別可以是父類方法返回值型別的子型別
  3. 訪問許可權, 子類方法的訪問許可權可以比父類方法訪問許可權更寬泛(更大)
    父類方法使用public修飾, 子類方法只能使用public
    父類方法使用protected修飾, 子類方法可以使用public或protected修飾
    一般情況下,如果需要子類覆蓋的方法,許可權至少是protected
  4. 異常處理 , 子類方法不能丟擲比父類方法異常更大的異常
    如果父類方法沒有丟擲異常, 子類方法不能丟擲異常
    如果父類方法宣告丟擲了異常,
    子類方法可以宣告丟擲相同的異常
    也可以丟擲父類方法異常的子異常
    也可以不丟擲異常

3.4 異常在開發中的應用(企業級登入時候異常處理可以解決一些使用者輸入錯誤資訊的提示效果)
自定義異常

  1. 定義一個類繼承Exception
  2. 一般提供兩個構造方法, 無參構造 與 有String引數的構造方法
  3. 在需要的位置通過throw丟擲異常物件
  4. 所在的方法通過throws宣告該異常
  5. 呼叫方法時,需要對該異常進行預處理

總結
1類與類之間的關係 (記住), 能夠使用Rose工具畫出各種關係圖
2瞭解什麼是內部類, 內部類編譯後生成獨立的位元組碼檔案: 外部類名$內部類名.class
3掌握介面的引用/抽象類的引用可以賦值匿名內部類物件,
4異常
異常是什麼?
能夠使用Rose工具畫出異常類結構圖
初步理解編譯時異常與執行時異常分類依據
執行時異常就是RuntimeException類的子類, RuntimeException類的子類都是執行時異常
編譯時異常是在定義方法時, 通過throws宣告的異常
執行時異常不需要進行預處理, 而是通過規範的程式碼進行規避
編譯時異常必須進行預處理, 否則編譯報錯

	異常處理的作用: 提高程式的健壯性

	異常處理的方式:
		try..catch捕獲處理
		throws丟擲處理
	如何選擇使用throws丟擲處理還是try..catch捕獲處理??
		定義方法時:
			如果方法體中通過throw丟擲了異常物件, 需要throws宣告丟擲該異常
			如果方法體中呼叫的其他方法有異常, 可以捕獲,也可以丟擲
		呼叫方法時
			如果被呼叫的方法有異常,一般需要進行捕獲處理
	方法覆蓋規則
	異常在開發中的應用(自定義異常)

程式碼:

  1. 介面/抽象類的引用可以賦值匿名內部類物件
  2. 異常的捕獲處理/ throws宣告丟擲
  3. 自定義異常
    性別只能賦值”男”或者 “女”, 如果是其他字串就丟擲異常