JAVA筆記整理-內部類與異常
一、內部類(inner class)
1、定義
在一個類中,定義另一個類的程式碼結構,通常定義在類內部的類稱為 “內部類” ,外面的類稱為“外部類” , 在邏輯關係上 內部類與外部類是從屬關係,例如 一個People類 存在收貨地址類(收貨人,收貨聯絡方式)
2、分類
2.1、 普通內部類(inner class),一個類A中定義另一個類B,其中類B就是類A的內部類,也是類A的一部分
//定義一個people類(外部類) public class People { private String pname="張三"; public void sayHello(){ System.out.println("Let us say Hello"); // 知識點1 :外部類的方法中,可以使用內部類的屬性、方法 Address address = new Address(); address.addressName ="湖北武漢"; address.contentName="張某某"; address.showAddressInfo(); } /** * 定義普通內部類 收貨地址類 */ class Address{ private String addressName;// 收貨地址 private String contentName;// 聯絡人 public void showAddressInfo(){ System.out.println("聯絡人:"+contentName + "--收貨地址:"+addressName); // 內部類的方法 可以直接訪問外部類的屬性 (由於通常情況屬性的訪問必須通過物件才可以使用,而內部類中可以直接訪問) System.out.println("訪問外部類的屬性:"+pname); } } }
注意兩點
- 外部類的方法中,可以直接訪問內部類的所有成員(包括私有)
- 內部類的方法中,也可以直接方法外部類的所有成員,當外部和內部的成員名相同時,就近原則訪問成員,或者引入外部類的物件訪問
2.2、 靜態內部類(static inner class): 在普通內部類基礎上,增加“static”關鍵字,與靜態方法相似,滿足靜態的要求
public class People{ /** * 2、定義靜態內部類 * 身份證資訊 */ static class Card{ private static String cardNo="3455434535345334"; private String cardName="張三"; // 定義靜態方法 public static void showCard(){ System.out.println("身份證號:"+ cardNo); } // 定義非靜態方法 public void showCard2(){ System.out.println("姓名:"+cardName + "身份證號:"+ cardNo); } } // 外部類的方法 訪問內部類的方法 public void method2(){ Card card = new Card(); // 對於靜態方法可以直接 類名.方法名 // 對於非靜態方法,需要建立Card類的物件訪問 card.showCard2(); } } 使用: // 2 建立靜態內部類的物件呼叫內部類方法 People.Card.showCard(); // 建立靜態內部類的物件 People.Card card = new People.Card(); card.showCard2();
2.3、方法內部類: 在一個方法中定義的類,其中這個類只屬於該方法,也只能在該方法中使用
/** * 3、方法內部類 (將一個類定義在方法裡面) */ public void method3(){ int score = 98; // 在這裡定義一個類 class MyClass{ String subject="Java"; public void getSubjectScore(){ //方法內部類中 也可以使用方法的屬性 System.out.println(pname+"的"+subject+":"+score); } } //呼叫方法裡面的類 MyClass mycls = new MyClass(); mycls.getSubjectScore(); }
People people = new People();
// 3 呼叫方法
people.method3();
注意:內部類中的class檔案 命名 外部類$內部類名.class
2.4 匿名內部類: 定義一個沒有類名,只有對方法的具體實現。通常它依賴於實現關係(介面)或繼承關係(父類)
a、基於實現關係
public interface MyInterface {
// 學習
public void study();
// 工作
public void work();
}
// 建立一個匿名類(讓介面的引用 指向匿名類的物件)
MyInterface person = new MyInterface() {
@Override
public void study() {
System.out.println("這個人也好好學習");
}
@Override
public void work() {
System.out.println("這個人也好好工作");
}
};
person.study();
person.work();
b、基於繼承關係
public class MyClass {
public void service(){
System.out.println("提供服務的方法。");
}
}
// 父類 new 一個 匿名類,這個匿名類是它的子類
MyClass cls = new MyClass(){
@Override //匿名類重寫父類的方法 service
public void service() {
System.out.println("這是子類的方法");
}
};
cls.service();
二、異常
1、異常的概述
異常定義: 在程式中,發生“不正常”的事件,導致程式無法正常執行,並使JVM中斷,稱為異常
生活中的異常: 早上起床上課,平時騎車20分鐘可以到達教室,由於天氣原因或者鬧鐘響了自動關閉,不能按時到達教室上課,遲到了,此時就屬於異常現象 。
捕獲異常: 當程式在執行時,發生了異常 ,為了讓程式正常執行,需要對異常捕獲(catch),稱之為捕獲異常
Java是面向物件的語言, 異常本身就是一個類(Exception),當發生異常時會建立異常物件,捕獲的就是該物件。
System.out.println("請輸入一個數字");
Scanner sc = new Scanner(System.in);
// 對可能發生的異常 進行處理
int num = sc.nextInt();
if(num%2==0){
System.out.println("這個數是偶數");
}
異常程式碼可能發生異常, 當用戶輸入非數字時, 導致程式丟擲一個異常物件 :
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:864)
2、異常關鍵字 以及層次關係
a、try: 試一試 ,將可能發生的程式碼使用try包裹 ,try不能單獨出現
b、catch : 捕獲異常, 當發生指定的異常物件時,執行catch程式碼
System.out.println("請輸入一個數字");
Scanner sc = new Scanner(System.in);
// 對可能發生的異常 進行處理
try {
int num = sc.nextInt(); // 發生異常後,try裡面的程式碼不再執行
if (num % 2 == 0) {
System.out.println("這個數是偶數");
}
System.out.println("結束");
}catch(Exception ee){// 對應的異常類 來捕獲對應的異常物件 ,不能確定異常類,可以使用父類Exception
System.out.println("你的輸入不正確");
}
System.out.println("程式繼續執行直到結束。。。。");
一個try + 多個catch
// 丟擲的異常 不能被catch捕獲,會發生什麼?
try {
int[] num = {1, 2, 3};
System.out.println(num[1]); // 沒有捕獲該異常物件,JVM依然終止執行
System.out.println(10/0);
}catch(NullPointerException ee){
System.out.println("這是空指標異常");
}catch(ArrayIndexOutOfBoundsException ee){
System.out.println("陣列下標越界異常");
}catch(Exception ee){
// 輸出異常 堆疊訊息 方便程式設計師排錯(儘可能避免使用者看見)
ee.printStackTrace();
System.out.println("系統繁忙!"+ee.getMessage());
}
System.out.println("程式結束");
c: finally : 異常之後的最終處理 (無法是否發生異常,程式都執行 )
try... finally 結構
try{
System.out.println("請輸入兩個數 ,計算兩個數相除");
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt();
int num2 = sc.nextInt();
double s = num1/num2; // 可能出錯
System.out.println(" try裡面結束,結果:"+s);
}finally{
System.out.println("無論是否發生異常,都會執行這個語句塊,一般用於資源回收");
}
try... catch...finally 結構
try {
System.out.println("請輸入兩個數 ,計算兩個數相除");
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt();
int num2 = sc.nextInt();
double s = num1 / num2; // 可能出錯
System.out.println(" try裡面結束,結果:" + s);
}catch(ArithmeticException ee){
ee.printStackTrace();
System.out.println("除數不能為0 !!");
}catch(Exception ee){
ee.printStackTrace();
System.out.println("系統繁忙!!!");
}finally {
System.out.println("用於資源回收。");
}
3、捕獲異常
try...catch...finally
4、丟擲異常
/**
* 根據下標訪問陣列元素
* @param array
* @param index
* @return
*/
public static int getEleByIndex(int [] array , int index){
// 丟擲異常: 可以在異常發生時 或發生之前 建立一個異常物件並丟擲
// 手動丟擲一個異常 throw new 異常類([異常訊息]);
if(index <0 || index > array.length-1){
//丟擲異常
throw new ArrayIndexOutOfBoundsException("你的下標越界了");
}
int n = array[index];
return n;
}
public static void main(String[] args) {
//陣列
int [] array = {2,1,4,5};
int index=4;
// 定義方法訪問下標的元素 此時會產生異常 並丟擲給方法的呼叫者
try {
int num = getEleByIndex(array, index);
System.out.println("訪問的元素:" + num);
}catch(ArrayIndexOutOfBoundsException ee){
System.out.println(ee.getMessage());
}
System.out.println("結束。。。");
}
5、異常分類
由於有些異常是不能直接丟擲的 ,需要先宣告才可以丟擲,異常可以分為兩大類:
1、 編譯期異常(check 異常或者檢查異常):在編譯期間檢查異常,如果沒有處理異常,則編譯出錯。
//建立一個檔案類的物件
File file = new File("d:/aaa.txt");
// 在寫程式碼(編譯之前)時 一定要處理的異常(try..catch 或者 throws),就是編譯時異常
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
這裡的IOException 就是 編譯期異常,需要手動處理的
2、執行期異常(runtime 異常或者執行異常):在執行期間檢查異常, 編譯期可以不處理異常。
// 在執行期間丟擲異常 不需要事先處理的 NullPointException是執行異常
String str=null;
System.out.println(str.length());
Exception中常用的異常類
- RuntimeException
- ArrayIndexOutOfBoundsException :陣列下標越界異常
- NullPointerException:空指標異常
- ArithmeticException: 算術異常
- NumberFormatException :數字格式化異常
- ClassNotFoundException: 類沒找到異常
- ClassCaseException: 類轉換異常
- 檢查異常(check Exception)
IOException :IO操作
FileNotFoundException: 檔案未找到異常
SQLException:
EOFException:讀寫檔案尾異常
DateFormatException:日期格式化異常
SocketException:SocketException
注意: 對於丟擲檢查異常,需要使用throws宣告,對於丟擲執行時異常,必須要使用throws宣告
宣告丟擲異常語法:
宣告丟擲異常語法:
public ... 方法名([引數]) throws 異常類1,異常類2{
// 通過throw丟擲 或 處理 檢查異常
}
/**
* 宣告丟擲異常語法:
* public ... 方法名([引數]) throws 異常類1,異常類2{
*
* }
*/
//建立檔案
public static void createFile() throws FileNotFoundException ,IOException {
File file = new File("d:/hello.txt");
if(file.exists()){
// 不能建立 ,需要提示使用者 該檔案存在
throw new FileNotFoundException("這個檔案已存在,不能建立");
}else{
//建立
file.createNewFile();
}
}
面試題: 關於 finally 和 return的執行順序問題?
回答: 當方法有返回值時,先執行fianlly,再return, 但是 finally的程式碼不會改變return結果
/**
* 方法有返回值 有 finally
* @param n
* @return
*/
public static int getNum(int n){
try{
if(n%2==0){
n++;
}else{
n--;
}
return n;
}catch(Exception ee){
System.out.println("catch--"+n);
return 0;
}finally {
// return 如果放在 try或catch中,不會受finally的改變
// 如果放在最下面,會受finally的改變
n++; // 5
System.out.println("fially----n:" + n); // 5
}
}
結果 返回
fially----n:5
4
6、自定義異常
1、為什麼需要使用自定義異常
在Java中每一個異常類都表示特定的異常型別, 例如 NullPointerException表示空指標 ,ArithmeticException表示算術異常, 但是sun公司提供的API中不可能將實際專案中的業務問題全部定義為已知的異常類 ,這是需要程式設計師根據業務需求來定製異常類,例如 使用者註冊,可以定義使用者註冊異常(RegisterException),分數不能為負數也可以定製異常(ScoreExcecption)。
2、什麼是自定義異常
在開發中根據自己的業務情況來定義異常類 , 靈活性較高,且方便易用。
3、如何實現自定義異常
a、定義編譯期異常類,建立一個類繼承 java.lang.Exception ;
b、定義執行期異常類,建立一個類繼承java.lang.RuntimeException;
4、案例分析:自定義異常應用
要求: 模擬使用者註冊操作, 使用者輸入使用者名稱 ,驗證使用者名稱是否存在,如果存在,則丟擲一個異常訊息 “親,該使用者已存在,不能註冊” ,通過自定義異常提示訊息
public class RegisterException extends Exception {
public RegisterException(){
}
public RegisterException(String message){
// 將message 賦值給父類的構造
super(message); // 將message賦值給父類的 屬性,可通過getMessage()方法
}
}
public class TestRegister {
// 模擬已存在的使用者
String [] users = {"張三","李四","王五"};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入你要註冊的使用者:");
String uname = sc.next();
TestRegister obj = new TestRegister();
try {
// 呼叫方法
obj.checkUserName(uname);
System.out.println("註冊成功");
} catch (RegisterException e) {
System.out.println("註冊失敗");
System.out.println(e.getMessage());
}
}
/**
* 檢查使用者是否存在
* @return true 表示通過
* 異常表示不通過
*/
public boolean checkUserName(String username) throws RegisterException{
// 使用foreach遍歷
/**
* for(資料型別 變數名 : 陣列名/集合名 ){
* 迴圈中的 變數名代表的就是陣列的元素
* }
*/
for(String u : users){
// 判斷u是否與 username相等 ,相等說明使用者存在,需要丟擲異常
if(u.equals(username)){
throw new RegisterException("親,"+username+" 已存在,不能註冊");
}
}
return true;
}
}