天天看點

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

目錄

一,面向對象基礎

1,面向對象概述

1.1 基本概念

1.2 舉個例子

1.3 三大思想

1.4 三大特征

2,類與對象的關系

3,類與對象的建立

3.1 類的建立

3.2 對象的建立

3.3 具體執行個體

4,對象建立記憶體

4.1 棧

4.2 堆

4.3 方法區

4.4 PC寄存器

4.5 本地方法棧

4.6 執行個體過程1

4.7 執行個體過程2

5,構造方法

5.1 概述

5.2 定義格式

5.3 構造方法設計 

6,方法的重載

6.2 普通方法的重載

6.2 構造方法的重載

7,匿名對象

二,面向對象進階

1,封裝

1.1 概述:

1.2 封裝原則:

1.3 舉例如下:

2,this關鍵字

2.1 概念

2.2 舉例

3,靜态static

3.1 概述

3.2 重點

3.3 舉例

4,包

4.1 介紹

4.2 使用規則

4.3 執行個體1

4.4 執行個體2

5,權限修飾符

6,代碼塊

6.1 代碼塊分類

6.2 構造代碼塊

6.3 靜态代碼塊

7,main方法詳解

三,面向對象進階

1,繼承格式

1.1 概念

1.2 格式

 1.3 繼承的限制

2,子類執行個體化記憶體分析

3,super詳解

4,重寫,重寫與重載的差別

4.1 重寫(Override)

4.2 重載(Overload)

4.3 差別

5,final關鍵字

5.1 final用于修飾屬性、變量。

5.2 final用于修飾類

5.3 final用于修飾方法

6,抽象類

6.1 概念

6.2 抽象方法

6.3 不能被執行個體化

6.4 執行個體

6.5 抽象類常見問題

6.6 抽象類與普通類的差別

7,接口多态

7.1 接口概念

7.2 面向接口程式設計思想

7.3 全局常量和抽象方法的簡寫

7.4 接口的實作

7.5 接口和抽象類的差別

 7.6 多态概念

7.7 多态的展現

7.8 多态的的使用:對象類型的轉換

8,instanceof

9,Object類概述

9.1 概念

9.2 Object的多态

10,toString

10.1 檢視文檔 

10.2 檢視對象的toString形式

10.3 重寫toString方法

10.4 重寫toString的快捷鍵方法

11,equals

11.1 概述

11.2 舉例 

12,内部類概述

12.1 概述

12.2 成員内部類

12.3 局部内部類

12.4 匿名内部類

12.5 靜态内部類

13,包裝類

13.1 概述

13.2 優點

13.3 裝箱和拆箱操作

13.4 字元串轉換

14,可變參數

15,遞歸概述

四,安裝IDEA

1,安裝IDEA

2,基本操作

五,異常處理

1,try-catch

1.1 問題引入

1.2 處理異常

1.3 finally常見面試問題

1.4 異常的體系結構

1.5 真實的異常處理場景

1.6 RuntimeExcepion與Exception的差別

2,throws

2.1 概念

2.2 什麼時候用throws/try-catch

3,throw

3.1 執行個體

4,自定義異常

4.1 非受檢異常(運作時異常)

4.2 受檢異常

5,快遞-views/快遞-完善

5.1 任務概述

5.2 編寫代碼

5.3 完整代碼

一,面向對象基礎

1,面向對象概述

1.1 基本概念

  • 面向對象(Object Oriented)是軟體開發方法。
  • 面向對象的概念和應用已超越了程式設計和軟體開發,是一種對現 實世界了解和抽象的方法,是計算機程式設計技術發展到一定階段後的産物。 
  • 面向對象是相對于面向過程來講的,指的是把 相關的資料和方法組織為一個整體 來看待,從更高的層次來進行系 統模組化,更貼近事物的自然運作模式。
面向過程到面向對象思想層面的轉變: 
  • 面向過程關注的是執行的過程,面向對象關注的是具備功能的對象。 
  • 面向過程到面向對象,是程式員思想上 從執行者到指揮者的轉變。

1.2 舉個例子

我們描述一個生活的場景: 

場景:當我們獨自生活時, 我們經常糾結一日三餐怎麼吃。

  • 面向過程: 每天親力親為: 買菜 - 做飯 - 吃飯 - 洗碗 的過程。 
  • 面向對象: 招聘一個保姆,每天等吃即可。 
場景更新: 假設你是一個富豪, 擁有一座占地3000畝地的莊園 ,不再是隻關注吃飯問題 , 還有花草樹木修剪,泳池維 護清洗,衛生打掃,洗衣做飯。。。。。。 
  • 面向過程: 此處省略看着就累的N字。 
  • 面向對象: 招聘一個管家, 然後讓管家招聘 園丁、泳池維護工、保姆等等。 
結論:
  • 從上述的栗子中, 我們發現面向過程,我們需要關注很繁瑣的過程 。
  •  而面向對象不用關注具體的細節,更關注的是統籌架構的問題。 
  • 其實我們進行大型應用開發時, 就如上述的例子一樣, 如果我們寫程式隻關注過程的話, 代碼量達到一定 層次以後, 就很難再編寫下去了。

1.3 三大思想

面向對象思想從概念上講分為以下三種:OOA、OOD、OOP 
  • OOA:面向對象分析(Object Oriented Analysis) 
  • OOD:面向對象設計(Object Oriented Design) 
  • OOP:面向對象程式(Object Oriented Programming

1.4 三大特征

封裝性:所有的内容對外部不可見
  • 将類的某些資訊隐藏在類内部,不允許外部程式直接通路,而是通過該類提供的方法來實作對隐藏資訊的操作和通路,常見的實作方式就是:getter、setter。
繼承性:将其他的功能繼承下來繼續發展
  • 繼承是類與類的一種關系,子類擁有父類的所有屬性和方法(除了private修飾的屬性不能擁有)進而實作了實作代碼的複用。
多态性:方法的重載本身就是一個多态性的展現(Java中的多态主要指引用多态和方法多态。)
  • 引用多态是指:父類引用可以指向本類對象,也可指向子類對象。引用多态的強大主要展現在調用屬性、方法時,可以根據引用具體指向的對象去調用,例如:子類中重寫了父類方法。
  •  方法多态:子類中可以重寫父類的方法,在調用方法時根據引用指向的子類對象決定調用哪個具體的方法。方法多态的強大主要展現在可以根據調用時參數的不同,而自主比對調用的方法,例如:重載。

2,類與對象的關系

類表示一個共性的産物,是一個綜合的特征,而對象,是一個個性的産物,是一個個體的特征。 (類似生活中的圖紙與實物的概念。) 

類必須通過對象才可以使用,對象的所有操作都在類中定義。 

類由屬性和方法組成: 

  • 屬性:就相當于人的一個個的特征 ;
  • 方法:就相當于人的一個個的行為,例如:說話、吃飯、唱歌、睡覺;

3,類與對象的建立

3.1 類的建立

1,類的定義格式:
class 類名稱{ 
    成員屬性 
    成員方法 
}
           
2,注意事項
  •  類必須編寫在.java檔案中。
  •  一個.java檔案中, 可以存在N個類, 但是隻能存在一個public修飾的類。
  •  .java檔案的檔案名稱 必須 與public修飾的類名 完全一緻;

3,屬性與方法定義格式

屬性定義格式: 

  • 資料類型 屬性名; 
  • 資料類型 屬性名 = 初始化值; 
方法定義格式: 
權限修飾符 傳回值類型 方法名(形式參數清單){ 
//方法體 
return 傳回值; 
}
           

3.2 對象的建立

一個類要想真正的進行操作,則必須依靠對象,對象的定義格式如下: 
  • 類名稱 對象名稱 = new 類名稱() ; 
如果要想通路類中的屬性或方法(方法的定義),則可以依靠以下的文法形式: 
  • 通路類中的屬性: 對象.屬性 ; 
  • 調用類中的方法: 對象.方法(實際參數清單) ;

3.3 具體執行個體

package com.kaikeba.demo2;
/**
 * class 類名{
 * 	成員屬性;
 * 	成員方法;
 * }
 * 
 * 類必須編寫在.java檔案中。
 * 一個.java檔案中, 可以存在N個類, 但是隻能存在一個public修飾的類。
 * .java檔案的檔案名稱 必須 與public修飾的類名 完全一緻;
 *
 */
public class Demo {

	public static void main(String[] args) {
		//建立對象的格式:
		//類名 對象名 = new 類名();
		Person p = new Person();
		//對象屬性指派
		//格式:	對象名.屬性名=值;
		p.name = "張三";
		p.age = 18;
		p.sex = '男';
		p.say();
		
		
		int s = p.sum(100, 200);
		System.out.println(s);
	}
}
/**
 * 類就像是圖紙
 */
class Person{
	//屬性 - 特征
	String name;
	int age;
	char sex;
	//方法 - 行為
	/**
	 * 定義格式:
	 * 傳回值類型 方法名稱(形式參數清單){
	 * 	方法體
	 * 	return 傳回值;
	 * }
	 * 
	 * 調用格式:
	 * 對象名.方法名稱(實際參數清單);
	 */
	
	void say() {
		System.out.println("自我介紹:我是"+name+" , 我的年齡:"+age+",我的性别:"+sex);
	}
	
	int sum(int x,int y) {
		int z = x+y;
		return z;
	}
	
	/*
	void xxx() {
		if(true) {
			return;    // 這裡的return表示方法的結束
		}
		System.out.println("哈哈");
	}
	*/
	
}
           

4,對象建立記憶體

4.1 棧

1,棧(Stack): Java中一個線程一個棧區。每一個棧中的元素都是私有的,不被其他棧所通路。 棧有後進先出的特點,棧中的資料大小與生存期都是确定的,缺乏靈活性,但是,存取速度比堆要快,僅次于CPU中的高存器...Java棧的區域很小 , 大概2m左右 , 特點是存取的速度特别快 ;

2,存儲速度快的原因:

  • 棧記憶體, 通過 '棧指針' 來建立空間與釋放空間 ! 
  • 指針向下移動, 會建立新的記憶體, 向上移動, 會釋放這些記憶體 !
  • 這種方式速度特别快 , 僅次于PC寄存器 ! 

3,但是這種移動的方式, 必須要明确移動的大小與範圍 , 明确大小與範圍是為了友善指針的移動 , 這是一個對于資料存儲的限制, 存儲的資料大小是固定的 , 影響了程式 的靈活性 ~ 。是以我們把更大部分的資料 存儲到了堆記憶體中 

4,棧中存儲的是: 

基本資料類型的資料(比如局部變量) 以及 引用資料類型的引用(比如數組的引用名,對象的引用名)! 

例如: 

  • int a =10; 
  • Person p = new Person(); 
  • 10存儲在棧記憶體中 , 第二句代碼建立的對象的引用(p)存在棧記憶體中

4.2 堆

存放的是類的對象(new出來的東西,成員變量) . (大小不固定)
  • Java是一個純面向對象語言, 限制了對象的建立方式: 所有類的對象都是通過new關鍵字建立 
  • new關鍵字, 是指告訴JVM , 需要明确的去建立一個新的對象 , 去開辟一塊新的堆記憶體空間: 
  • 堆記憶體與棧記憶體不同, 優點在于我們建立對象時 , 不必關注堆記憶體中需要開辟多少存儲空間 , 也不需要關注記憶體占用 時長 ! 
  • 堆記憶體中記憶體的釋放是由GC(垃圾回收器)完成的 
垃圾回收器 回收堆記憶體的規則: 
  • 當棧記憶體中不存在此對象的引用時,則視其為垃圾 , 等待垃圾回收器回收

4.3 方法區

存放的是
  • 類資訊 
  • 靜态的變量 
  • 常量 
  • 成員方法 
方法區中包含了一個特殊的區域 ( 常量池 )(存儲的是使用static修飾的成員)

4.4 PC寄存器

PC寄存器儲存的是 目前正在執行的 JVM指令的 位址 ! 

在Java程式中, 每個線程啟動時, 都會建立一個PC寄存器 !

4.5 本地方法棧

儲存本地(native)方法的位址 ! 

4.6 執行個體過程1

1,配置設定記憶體,并且修改屬性的值;
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,建立新的對象b2,指向舊對象b1,并且更新屬性name的值
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,程式執行完畢,引用資料從棧中彈出,棧記憶體中不存在此對象的引用時,等待垃圾回收器回收;
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

4.7 執行個體過程2

1,建立兩個新對象
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,引用資料b2指向b1,b2原先指向的對象被當作垃圾釋放;
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

5,構造方法

5.1 概述

回顧對象的建立
  • Person p = new Person(); 在右側Person後面出現的小括号, 其實就是在調用構造方法 !
作用:
  • 用于對象初始化。 
執行時機:
  • 在建立對象時,自動調用 
特點:
  • 所有的Java類中都會至少存在一個構造方法 
  • 如果一個類中沒有明确的編寫構造方法, 則編譯器會自動生成一個無參的構造方法, 構造方法中沒有任何的代 碼! 
  • 如果自行編寫了任意一個構造器, 則編譯器不會再自動生成無參的構造方法

5.2 定義格式

定義的格式: 

與普通方法基本相同, 差別在于: 方法名稱必須與類名相同, 沒有傳回值類型的聲明 ! 

案例:

public class Demo3{ 
    public static void main(String[] args){ 
        Person p = new Person(); 
        p = new Person(); 
        p = new Person(); 
        p = new Person(); 
    } 
}
class Person{ 
    public Person(){ 
        System.out.println("對象建立時,此方法調用"); 
    } 
}
           

5.3 構造方法設計 

建議自定義無參構造方法,不要對編譯器形成依賴,避免錯誤發生。 

當類中有非常量成員變量時,建議提供兩個版本的構造方法,一個是無參構造方法,一個是全屬性做參數的構造方法。 

當類中所有成員變量都是常量或者沒有成員變量時,建議不提供任何版本的構造。

6,方法的重載

6.2 普通方法的重載

方法名稱相同, 參數類型或參數長度不同, 可以完成方法的重載 ! 

方法的重載與傳回值無關! 方法的重載 ,可以讓我們在不同的需求下, 通過傳遞不同的參數調用方法來完成具體的功能

package com.kaikeba.demo2;

public class Demo5 {

	public static void main(String[] args) {
		Math m = new Math();
		int num = m.sum(100, 500);
		System.out.println(num);
		
		double num2 = m.sum(10.5, 20.6);
		System.out.println(num2);
	}

}
// 命名規範 見名知意
class Math{
	/**
	 * 一個類中定義的方法, 是允許重載 (相同的方法名稱)
	 * 
	 * 1、方法名稱相同
	 * 2、參數清單長度  或 參數清單類型 或 (參數類型順序不同)
	 * 
	 * 注意: 與傳回值類型無關
	 * 
	 */
	int sum(int x,int y) {
		int z = x+y;
		return z;
	}
	
	double sum(double x,double y) {
		double z = x+y;
		return z;
	}
	
	double sum(int x,double y) {
		double z = x+y;
		return z;
	}
	
	double sum(double y,int x) {
		double z = x+y;
		return z;
	}
	
}
           

6.2 構造方法的重載

一個類, 可以存在多個構造方法 : 
  • 參數清單的長度或類型不同即可完成構造方法的重載 ~ 
  • 構造方法的重載 ,可以讓我們在不同的建立對象的需求下, 調用不同的方法來完成對象的初始化!
package com.kaikeba.demo2;

public class Demo6 {

	public static void main(String[] args) {
		Person3 p = new Person3("張三",18);
		p.say();
		
		Person3 p2 = new Person3("李四");
		p2.say();
	}

}
class Person3{
	
	Person3(String name2,int age2){
		name = name2;
		age = age2;
	}
	
	Person3(String name2){
		name = name2;
	}
	
	String name;
	int age;
	
	void say() {
		System.out.println("自我介紹: 姓名:"+name+", 年齡:"+age);
	}
	
}
           

7,匿名對象

沒有對象名稱的對象 就是匿名對象。 (沒有對象名、引用名,是以是以棧中無相關記錄,故隻能使用一次)
  • 匿名對象隻能使用一次,因為沒有任何的對象引用,是以将稱為垃圾,等待被G·C回收。 
  • 隻使用一次的對象可以通過匿名對象的方式完成,這一點在以後的開發中将經常使用到。
package com.kaikeba.demo2;

public class Demo7 {

	/**
	 * 匿名	:	沒有名字(沒有對象名 沒有引用名,是以棧中無相關記錄,故隻能使用一次)
	 */
	public static void main(String[] args) {
		int num = new Math2().sum(100, 200);	// 沒有給對象名稱 而是直接建立對象并使用方法
		System.out.println(num);
	}
}

class Math2{
	
	int sum(int x,int y) {
		return x+y;
	}
}
           
每次new都是在堆中建立了一個新的記憶體區:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

二,面向對象進階

1,封裝

1.1 概述:

  • 封裝的意義在于保護或者防止代碼(資料)被我們無意中破壞。
  • 保護成員屬性,不讓類以外的程式直接通路和修改;

1.2 封裝原則:

  • 隐藏對象的屬性和實作細節,僅對外公開通路方法,并且控制通路級别

1.3 舉例如下:

1,觀察如下代碼: 
class Person{ 
	private String name ; // 表示姓名 
	private int age ; // 表示年齡 
	void tell(){ 
		System.out.println("姓名:" + name + ";年齡:" + age) ; 
	} 
};
public class Demo{ 
	public static void main(String args[]){ 
		Person per = new Person() ; 
		per.name = "張三" ; 
		per.age = -30 ; 
		per.tell() ; 
	} 
};
           

2,可以發現,per.age = -30;出現邏輯錯誤(年齡不可能為負數);

3,在開發中, 為了避免出現邏輯錯誤, 我們建議對所有屬性進行封裝,并為其提供setter及getter方法進行設定和取得 操作。

Eclipse中對setter及getter方法建立提供了兩種快捷方式:

方法一:

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
方法二:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
4,修改後的代碼如下:(private修飾屬性)
class Person{ 
	private String name ; // 表示姓名 
	private int age ; // 表示年齡 
	void tell(){ 
		System.out.println("姓名:" + getName() + ";年齡:" + getAge()) ; 
	}
	public void setName(String str){ 
		name = str ; 
	}
	public void setAge(int a){ 
	    if(a>0&&a<150) 
		age = a ;
            else{
                System.out.println("年齡設定不合理,自動設定為1");
                age = 1;
            } 
	}
	public String getName(){ 
		return name ; 
	}
	public int getAge(){ 
		return age ; 
	} 
};
public class Demo10{ 
	public static void main(String args[]){ 
		Person per = new Person() ;
		per.setName("張三") ; 
		per.setAge(-30) ; 
		per.tell() ; 
	} 
};
           
修改年齡屬性時需要調用函數, 是以可以通過函數來控制輸入的參數是否合理,并給出相應提示,大大的降低出錯機率:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2,this關鍵字

2.1 概念

在Java基礎中,this關鍵字是一個最重要的概念。使用this關鍵字可以完成以下的操作: 
  • 調用類中的屬性 ;
  • 調用類中的方法或構造方法 (在一個構造方法中,調用另一一個構造方法時, 調用的代碼必須編寫在構造方法的第一 行。因為在調用有參構造方法之前,對象尚未建立完畢,這時使用其他語句會報錯);
  • 表示目前對象;

2.2 舉例

1,聲明全參構造函數時,如果傳遞的參數和屬性名稱一緻,就會出現問題: 
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,解決方法:this.屬性名
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,此外,還可以通過this在無參構造方法中調用有參構造方法
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
4,注意:在一個構造方法中,調用另一一個構造方法時, 調用的代碼必須編寫在構造方法的第一 行;
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

3,靜态static

3.1 概述

static表示“靜态”的意思,可以用來修飾成員變量和成員方法(後續還會學習 靜态代碼塊 和 靜态内部類)。 

static的主要作用在于建立獨立于具體對象的域變量或者方法 

簡單了解: 

  • 被static關鍵字修飾的方法或者變量不需要依賴于對象來進行通路,隻要類被加載了,就可以通過類名去進行訪 問; 
  • 并且不會因為對象的多次建立 而在記憶體中建立多份資料;

3.2 重點

靜态成員 在類加載時加載并初始化。 

無論一個類存在多少個對象 , 靜态的屬性, 永遠在記憶體中隻有一份( 可以了解為所有對象公用 ) 

在通路時: 靜态不能通路非靜态 , 非靜态可以通路靜态 !(靜态表示對象未建立也可調用,而非靜态必須等到對象建立完畢。是以使用靜态時,對象可能還未建立,是以不能通路非靜态)

3.3 舉例

1,假設員工有屬性:姓名、公司。聲明若幹個對象時,原先的做法如下:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2,當公司遷址,那麼每個對象中的位址屬性都需要進行修改(時間開銷大)。此外公司位址都是相同的,不同對象重複的建立位址變量,有浪費空間的嫌疑(空間開銷大);

目前記憶體狀況如下:

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

3,解決方法:static修飾

使用static修飾的變量,存放在方法區中:

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
 4,static修飾的變量,可以了解為類的屬性,直接通過類名來調用,是以在建立對象之前就可以調用
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

4,包

4.1 介紹

1、把功能相似或相關的類或接口組織在同一個包中,友善類的查找和使用。 

2、包如同檔案夾一樣,不同的包中的類的名字是可以相同的,當同時調用兩個不同包中相同類名的類時,應該加上包名 加以差別。是以,包可以避免名字沖突。 

3、包也限定了通路權限,擁有包通路權限的類才能通路某個包中的類。

4.2 使用規則

1,包中java檔案的定義: 
  • 在.java檔案的首部, 必須編寫類所屬哪個包, 
  • 格式: package 包名; 
2,包的定義: 
  • 通常由多個單詞組成, 所有單詞的字母小寫, 單詞與單詞之間使用.隔開 ,一般命名為“com.公司名.項目 名.子產品名....”。 
3,規範由來: 
  • 由于Java面向對象的特性,每名Java開發人員都可以編寫屬于自己的Java Package,為了保障每個Java Package命名的唯一性,在最新的Java程式設計規範中,要求開發人員在自己定義的包名前加上唯一的字首。由于網際網路上 的域名稱是不會重複的,是以多數開發人員采用自己公司在網際網路上的域名稱作為自己程式包的唯一字首。例如: com.java.xxx

4.3 執行個體1

1,建立包
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,找到包對應的檔案夾
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,可以看出:包實際上就是檔案夾

4.4 執行個體2

1,如何實用工具包?

當所需的工具類不在目前檔案夾中時,需要通過import進行導包;

如果不想通過import導包的話,也可以通過使用類全名的方法實作相同的功能;

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,什麼情況不需要導包?
  • 一些常用的系統包,比如String類型,包含在java.lang包中;
  • 使用目前包中的類;

5,權限修飾符

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

6,代碼塊

6.1 代碼塊分類

普通代碼塊 
  • 在執行的流程中 出現的 代碼塊, 我們稱其為普通代碼塊。 
構造代碼塊 
  • 在類中的成員代碼塊, 我們稱其為構造代碼塊, 在每次對象建立時執行, 執行在構造方法之前。 
靜态代碼塊 
  • 在類中使用static修飾的成員代碼塊, 我們稱其為靜态代碼塊, 在類加載時執行。 每次程式啟動到關閉 ,隻會 執行一次的代碼塊。 
同步代碼塊 
  • 在後續多線程技術中學習。 
面試題:構造方法 與 構造代碼塊 以及 靜态代碼塊的執行順序: 靜态代碼塊 --> 構造代碼塊 --> 構造方法

6.2 構造代碼塊

1,随着對象的每次建立,執行一次。 且執行在構造方法之前:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2,為什麼需要構造代碼塊呢?

與構造方法不同,構造方法不一定會被執行(構造方法可能會重載,這樣使用無參構造方法就不會調用一參或兩參的構造方法);

是以當多個構造方法需要同一種操作時,可以使用代碼塊(可以有多個);

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

6.3 靜态代碼塊

在代碼塊前加static;

靜态代碼塊,随着類的加載 (第一次使用) ,靜态代碼塊執行。

因為類隻加載一次,是以靜态代碼塊隻執行一次。

舉例如下:

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

7,main方法詳解

main()方法一直寫到了今天: 

public static void main(String args[]) 

以上的各個參數的含義如下: 

  • · public:表示公共的内容,可以被所有操作所調用 
  • · static:表示方法是靜态的,可以由類名稱直接調用。java StaticDemo09 
  • · void:表示沒有任何的傳回值操作 
  • · main:系統規定好的方法名稱。如果main寫錯了或沒有,會報錯:NoSuchMethodError: main 
  • · String[] args:字元串數組,接收參數的 
public class StaticDemo10{ 
    public static void main(String args[]){ 
        for(int i=0;i<args.length;i++){ 
        System.out.println(args[i]) ; 
    } 
} 
           
所有的參數在執行類的時候以空格進行分割。 
java StaticDemo10 1 2 3 4 5 6 7 
           

但是,如果現在我要輸入的是以下幾種參數“hello world”、“hello vince”、“hello mjw”。

因為以空格分割,是以以上的三組參數會當做六組參數輸入,那麼此時如果要想完成有空格的内容輸入,則參數需 要使用“"”括起來。 

java StaticDemo10 "hello world" "hello vince" "hello mjw"
           

三,面向對象進階

1,繼承格式

1.1 概念

繼承是java面向對象程式設計技術的一 塊基石,因為它允許建立分等級層次的類。

繼承就是子類繼承父類的特征和行為,使得子類對象(執行個體)具有父類的執行個體域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。

1.2 格式

class 父類 {

}
class 子類 extends 父類 {

}
           

 1.3 繼承的限制

Java中隻有單繼承,多重繼承(C想繼承B和A,可以C繼承B,B繼承A),沒有多繼承(同時繼承多個父類。因為不同的父類可能有相同的特征時,如何選擇繼承誰的)

2,子類執行個體化記憶體分析

1,假設現在有一個父類Person,子類Student繼承父類Person。當建立Student對象時Student s = new Student(),便在棧中建立引用,在堆中建立Student空間:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,但實際上,并不是直接打開Student空間,而是先檢視其有哪些父(這裡是Person類)。于是先建立Person對象,建立完畢後再建立Student,并添加super變量/屬性;
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,super中存放的值就是Person對象的記憶體位址,是以可以通過super操作Person類;
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
4,假設setName函數和name屬性都在Person類中。當調用s.setName("張三");時,先找Student有沒有setName的方法,如果沒有就在super中找(這樣可以規定方法使用的優先級,相當于重寫),如果沒有,就在Person中的super找,以此類推。是以 s.setName("張三") 《=》s.super.setName("張三")。是以最終是在Person中修改了name的值;
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
5,繼承時隻能繼承共有的比如用public,protected修飾的屬性和方法,default和private修飾的無法直接使用。
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

3,super詳解

super:

通過super,可以通路父類構造方法

  • 調用super構造方法的代碼,必須寫在子類構造方法的第一行。(類似于this中相關的用法)

通過super,可以通路父類的屬性

通過super,可以通路父類的方法

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

4,重寫,重寫與重載的差別

4.1 重寫(Override)

重寫(override) 規則:(子父類之間)

1,參數清單必須完全 與被重寫方法的相同:

2,傳回類型必須完全與被重寫方法的傳回類型相同:

3,通路權限不能比父類中被重寫的方法的通路權限更低。例如:如果父類的一個方法被聲明為public,那麼在子類中重與該方法就不能聲明為protected.

4,父類的成員方法隻能披它的子類重寫。(如果兩個類之間沒有關系,因為沒有繼承,是以不算重寫)

5,聲明為static和privete的方法不能被重寫,但是能夠被再次聲明。(靜态static的方法與對象無關。私有private不能被繼承,是以無法重寫)

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

4.2 重載(Overload)

見本文 一,6 

4.3 差別

1,發生的位置:
  • 重載:一個類中
  • 重寫:子父類中
2,參數清單限制
  • 重載:必須不同
  • 重寫:必須相同
3,傳回值類型
  • 重載:與傳回值類型無關
  • 重寫:傳回值類型必須一緻
4,通路權限
  • 重載:與通路權限無關
  • 重寫:子的方法權限不能小于父的方法權限
5,異常處理
  • 重載:與異常無關
  • 重寫:異常範圍可以更小,但是不能抛出新的異常

5,final關鍵字

5.1 final用于修飾屬性、變量。

  • 變量成為常量,無法再次進行指派
  • final修飾的局部變量(在方法内部),隻能指派一 次(可以先聲明後指派)
    02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
  • final修飾的是成員屬性,必須在聲明時指派。                    
    02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
  • 全局常量( public static final )。
補充:常量的命名規範
  • 由1個或多個單詞組成,單詞與單詞之 間必須使用下劃線隔開,單詞中所有字母大寫。比如SQL_INSERT

5.2 final用于修飾類

final修飾的類,不能被繼承。

5.3 final用于修飾方法

final修飾的方法,不能被子類重寫。

6,抽象類

6.1 概念

抽象類必須使用abstract class聲明 

一個抽象類中可以沒有抽象方法。抽象方法必須寫在抽象類或者接口中。 

格式:

abstract class 類名{ 
    // 抽象類
}
           
比如,在設計父類Person時,有一個方法用來描述說話方式,然而子類可能有很多比如學生、護士、企業家等等,他們對這個方法的需求并不統一,是以父類不知如何設計(無法确定的部分)

6.2 抽象方法

隻聲明而未實作的方法稱為抽象方法(未實作指的是:沒有“{}”方法體),抽象方法必須使用abstract關 鍵字聲明。 

格式:

abstract class 類名{ // 抽象類 
    public abstract void 方法名() ; // 抽象方法,隻聲明而未實作 
}
           

6.3 不能被執行個體化

類相當于一個圖紙,當類中有不确定的部分時,便不能依據圖紙做出相應的執行個體,也就是不能被執行個體化。

在抽象類的使用中有幾個原則: 

  • · 抽象類本身是不能直接進行執行個體化操作的,即:不能直接使用關鍵字new完成。 
  • · 一個抽象類必須被子類所繼承,被繼承的子類(如果不是抽象類)則必須重寫抽象類中的全部抽象方法。

6.4 執行個體

程式設計規範:建議一個.java檔案隻編寫一個類,且類通過public修飾。

1,測試類Demo,抽象類Person;

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,編寫子類Student
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,編寫子類Nurse
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
4,編寫測試方法:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

5,抽象類的好處

假設現在有一個大型項目,當項目中部分子產品未明确功能時,如果是以而暫停項目的開展程序,将會非常低效,是以将不确定的部分編寫為抽象類(抽象類也不常用,後續中的接口應用更加普遍)

6.5 抽象類常見問題

1、 抽象類能否使用final聲明? 
  • 不能,因為final屬修飾的類是不能有子類的 , 而抽象類必須有子類才有意義,是以不能。 
2、 抽象類能否有構造方法? 
  • 能有構造方法,而且子類對象執行個體化的時候的流程與普通類的繼承是一樣的,都是要先調用父類中的構造方法(預設是無參的),之後再調用子類自己的構造方法。(建立子類對象時,是先建立父類的對象,然後再建立子類對象,并添加super屬性)
比如在抽象類中添加無參構造方法:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
執行測試類:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

6.6 抽象類與普通類的差別

1、抽象類必須用public或protected修飾(如果為private修飾,那麼子類則無法繼承,也就無法實作其抽象方法)。 預設預設為 public 

2、抽象類不可以使用new關鍵字建立對象, 但是在子類建立對象時, 抽象父類也會被JVM執行個體化。 

3、如果一個子類繼承抽象類,那麼必須實作其所有的抽象方法。如果有未實作的抽象方法,那麼子類也必須定義為 abstract類

7,接口多态

7.1 接口概念

如果一個類中的全部方法都是抽象方法,全部屬性都是全局常量,那麼此時就可以将這個類定義成一個接口。

格式:

interface 接口名稱{ 
    全局常量 ; 
    抽象方法 ; 
}
           
 如果一個接口要想使用,必須依靠子類。 子類(如果不是抽象類的話)要實作接口中的所有抽象方法。

7.2 面向接口程式設計思想

這種思想是接口是定義(規範,限制)與實作(名實分離的原則)的分離。 (從宏觀角度設計好,定義好規範後再設計,某一環節出現問題,直接替換即可)

優點:

  • 1、 降低程式的耦合性 
  • 2、 易于程式的擴充 
  • 3、 有利于程式的維護

7.3 全局常量和抽象方法的簡寫

因為接口本身都是由全局常量和抽象方法組成 , 是以接口中的成員定義可以簡寫:

1、全局常量編寫時, 可以省略public、static、final 關鍵字,例如: 

public static final String INFO = "内容" ; 

簡寫後: String INFO = "内容" ; 

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

斜體加粗表示

2、抽象方法編寫時, 可以省略 public、abstract 關鍵字, 例如: 

public abstract void print() ; 

簡寫後: void print() ;

7.4 接口的實作

接口因為都是抽象部分, 不存在具體的實作, 是以允許多繼承:

格式: 

class 子類 implements 父接口1,父接口2...{ 

}
           
以上的代碼稱為接口的實作。那麼如果一個類即要實作接口,又要繼承抽象類的話,則按照以下的格式編寫即可:
class 子類 extends 父類 implements 父接口1,父接口2...{ 

}
           

7.5 接口和抽象類的差別

1、抽象類要被子類繼承,接口要被類實作。 

2、接口隻能聲明抽象方法,抽象類中可以聲明抽象方法,也可以寫非抽象方法。 

3、接口裡定義的變量隻能是公共的靜态的常量,抽象類中的變量是普通變量。 

4、抽象類使用繼承來使用, 無法多繼承。 接口使用實作來使用, 可以多實作 

5、抽象類中可以包含static方法 ,但是接口中不允許(靜态方法不能被子類重寫,是以接口中不能聲明靜态方法) 

6、接口不能有構造方法,但是抽象類可以有

 7.6 多态概念

多态:就是對象的多種表現形式,(多種展現形态)

7.7 多态的展現

對象的多态性,從概念上非常好了解,在類中有子類和父類之分,子類就是父類的一種形态 ,對象多态性就從此而來。 

ps: 方法的重載 和 重寫 也是多态的一種, 不過是方法的多态(相同方法名的多種形态)。 

  • 重載: 一個類中方法的多态性展現 
  • 重寫: 子父類中方法的多态性展現。

7.8 多态的的使用:對象類型的轉換

類似于基本資料類型的轉換: 
  • 向上轉型:将子類執行個體變為父類執行個體 
格式:父類 父類對象 = 子類執行個體 ; 
  • 向下轉型:将父類執行個體變為子類執行個體 

格式:子類 子類對象 = (子類)父類執行個體 ;(類似于強制轉化)

例1,父類的對象指向子類的對象,即小範圍的資料可用大範圍的來表示: 

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
例2,向上轉型之後,護士的本質還是護士,學生的本質還是學生,如果用學生的對象指向護士的上轉型對象就會出錯:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
例3,多态的實際應用。
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

8,instanceof

作用:判斷某個對象是否是指定類的執行個體,則可以使用instanceof關鍵字 

格式:執行個體化對象 instanceof 類 //此操作傳回boolean類型的資料

舉例:在方法中有時會提前約定對象所屬的類,這時如果不判斷類型就會出錯

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
 解決方法
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

9,Object類概述

9.1 概念

Object類是所有類的父類(基類),如果一個類沒有明确的繼承某一個具體的類,則将預設繼承Object類。 

例如我們定義一個類: 

public class Person{ 
}
           
其實它被使用時 是這樣的: 
public class Person extends Object{ 
}
           

9.2 Object的多态

有了前面的鋪墊,可以看出,使用Object可以接收任意的引用資料類型;

舉例1,傳入String資料類型

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

10,toString

檢視類的某些方法:

方法一:Ctrl+滑鼠左鍵檢視類的源碼

方法二:檢視API文檔

10.1 檢視文檔 

搜尋Object,找到toString方法 
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

10.2 檢視對象的toString形式

直接輸出一個對象 
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
檢視println函數
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
檢視valueOf函數
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

10.3 重寫toString方法

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

運作檢視
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
如何區分對象
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
運作效果
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
建議:重寫所有類的toString方法

10.4 重寫toString的快捷鍵方法

1,Shift+Alt+S

2,選擇生成toString

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,勾選作為辨別的屬性
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
4,自動生成的toString函數
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
5,運作效果
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

11,equals

11.1 概述

建議重寫Object中的equals(Object obj)方法,此方法的作用:訓示某個其他對象是否“等于”此對象。 

Object的equals方法:實作了對象上最具差別的可能等價關系; 也就是說,對于任何非空引用值x和y ,當且僅當 x和y引用同一對象( x == y具有值true )時,此方法傳回true 。 

equals方法重寫時的五個特性: 

  • 自反性 :對于任何非空的參考值x , x.equals(x)應該傳回true 。 
  • 對稱性 :對于任何非空引用值x和y , x.equals(y)應該傳回true當且僅當y.equals(x)回報true 。 
  • 傳遞性 :對于任何非空引用值x , y和z ,如果x.equals(y)回報true個y.equals(z)回報true ,然後 x.equals(z)應該傳回true 。 
  • 一緻性 :對于任何非空引用值x和y ,多次調用x.equals(y)始終傳回true或始終傳回false ,前提是未修改對象 上的equals比較中使用的資訊。 
  • 非空性 :對于任何非空的參考值x , x.equals(null)應該傳回false 。

11.2 舉例 

1,直接使用==,比較的是記憶體中的位址,是以隻要不是同一個東西,就會傳回false
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,直接使用equals,仍然會報錯
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,檢視equals的實作方式,發現本質上仍是==,是以需要重寫
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
4,重寫equals方法
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
5,簡化方法
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
6,運作結果
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
7,快捷鍵:Shift+Alt+S,選擇下列選項
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

12,内部類概述

12.1 概述

在Java中,可以将一個類定義在另一個類裡面或者一個方法裡面,這樣的類稱為内部類。 

廣泛意義上的内部類一般來說包括這四種: 

  • 1、成員内部類 
  • 2、局部内部類 
  • 3、匿名内部類 
  • 4、靜态内部類

12.2 成員内部類

 成員内部類是最普通的内部類,它的定義為位于另一個類的内部,形如下面的形式
class Outer { 
    private double x = 0; 
    public Outer(double x) { 
        this.x = x; 
    }
    class Inner { //内部類 
        public void say() { 
            System.out.println("x="+x); 
        } 
    } 
}
           

特點: 成員内部類可以無條件通路外部類的所有成員屬性和成員方法(包括private成員和靜态成員)。 

不過要注意的是,當成員内部類擁有和外部類同名的成員變量或者方法時,會發生隐藏現象,即預設情況下通路 的是成員内部類的成員。如果要通路外部類的同名成員,需要以下面的形式進行通路: 

  • 外部類.this.成員變量 
  • 外部類.this.成員方法
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

12.3 局部内部類

局部内部類是定義在一個方法或者一個作用域裡面的類,它和成員内部類的差別在于局部内部類的通路僅限于方法内或 者該作用域内 

注意:局部内部類就像是方法裡面的一個局部變量一樣,是不能有public、protected、private以及static修飾符的。

例1,使用介紹

1,比如原先因為不确定一些操作,定義一個接口,這時要一個方法需要使用這個接口(

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,如果正确實作,還需要額外寫一個類,顯得過域麻煩,這時就可以使用局部内部類
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

3,簡單來說就是參數需要對象,但不知道該new什麼時,且隻用到一次,可以使用局部内部類。

例2,實際應用場景

1,當給一個視窗添加監聽器時,發現需要傳入一個參數,參數的類型為接口

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,編寫局部内部類
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,修改對應方法即可

12.4 匿名内部類

 屬于局部内部類的一種。匿名内部類由于沒有名字,是以它的建立方式有點兒奇怪。建立格式如下:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

在這裡我們看到使用匿名内部類我們必須要繼承一個父類或者實作一個接口,當然也僅能隻繼承一個父類或者實作一 個接口。同時它也是沒有class關鍵字,這是因為匿名内部類是直接使用new來生成一個對象的引用。當然這個引用是隐 式的。

在使用匿名内部類的過程中,我們需要注意如下幾點: 

  • 1、使用匿名内部類時,我們必須是繼承一個類或者實作一個接口,但是兩者不可兼得,同時也隻能繼承一個類或 者實作一個接口。 
  • 2、匿名内部類中是不能定義構造函數的。 
  • 3、匿名内部類中不能存在任何的靜态成員變量和靜态方法。 
  • 4、匿名内部類為局部内部類,是以局部内部類的所有限制同樣對匿名内部類生效。 
  • 5、匿名内部類不能是抽象的,它必須要實作繼承的類或者實作的接口的所有抽象方法。 
  • 6、隻能通路final型的局部變量
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

為什麼隻能通路final型局部變量

1,使用局部變量,對變量二次指派時報錯

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,内部類也是一個類,是以編譯結束後也會生成一個内部類對應的位元組碼檔案,此時備份了變量的值,如果外部變量發生了改變,就會造成前後不一緻的情況
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

12.5 靜态内部類

靜态内部類也是定義在另一個類裡面的類,隻不過在類的前面多了一個關鍵字static。 

靜态内部類是不需要依賴于外部類對象的,這點和類的靜态成員屬性有點類似,并且它不能使用外部類的非static成員 變量或者方法.

 例1

1,建立靜态内部類對象

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,靜态内部類執行個體化
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,它不能使用外部類的非static成員 變量或者方法
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

13,包裝類

13.1 概述

在Java中有一個設計的原則“一切皆對象”,那麼這樣一來Java中的一些基本的資料類型,就完全不符合于這種設計思 想,因為Java中的八種基本資料類型并不是引用資料類型,是以Java中為了解決這樣的問題,引入了八種基本資料類型 的包裝類。
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
以上的八種包裝類,可以将基本資料類型按照類的形式進行操作。 但是,以上的八種包裝類也是分為兩種大的類型的: 
  • · Number:Integer、Short、Long、Double、Float、Byte都是Number的子類表示是一個數字。 
  • · Object:Character、Boolean都是Object的直接子類。
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

13.2 優點

1,可以作為對象參數進行傳遞,友善了基本資料類型與引用資料類型的互動(這裡參數直接傳10,會自動裝箱,變為Integer對象,然後傳遞)
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,可以有許多方法提供使用
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

13.3 裝箱和拆箱操作

以下以Integer和Float為例進行操作 
  • 将一個基本資料類型變為包裝類,那麼這樣的操作稱為裝箱操作。 
  • 将一個包裝類變為一個基本資料類型,這樣的操作稱為拆箱操作, 
因為所有的數值型的包裝類都是Number的子類,Number的類中定義了如下的操作方法,以下的全部方法都是進行拆箱的操 作。
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

裝箱操作:

在JDK1.4之前 ,如果要想裝箱,直接使用各個包裝類的構造方法即可,例如:

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
在JDK1.5,Java新增了自動裝箱和自動拆箱,而且可以直接通過包裝類進行四則運算和自增自建操作。例如:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
程式執行個體
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

13.4 字元串轉換

使用包裝類還有一個很優秀的地方在于:可以将一個字元串變為指定的基本資料類型,此點一般在接收輸入資料上使用 較多。 

在Integer類中提供了以下的操作方法: 

  • public static int parseInt(String s) :将String變為int型資料 
在Float類中提供了以下的操作方法: 
  • public static float parseFloat(String s) :将String變為Float 
在Boolean 類中提供了以下操作方法: 
  • public static boolean parseBoolean(String s) :将String變為boolean
舉例
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,将字元串轉換為int
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

14,可變參數

一個方法中定義完了參數,則在調用的時候必須傳入與其一一對應的參數,但是在JDK 1.5之後提供了新的功能,可以根 據需要自動傳入任意個數的參數。
傳回值類型 方法名稱(資料類型…參數名稱){ 
    //參數在方法内部 , 以數組的形式來接收 
}
           
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
注意: 可變參數隻能出現在參數清單的最後。
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

15,遞歸概述

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

四,安裝IDEA

1,安裝IDEA

1,進入官網https://www.jetbrains.com/products.html#type=ide,選擇IDEA
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,下載下傳
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,下載下傳完之後安裝
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
4,注冊(用郵箱注冊,通過郵箱驗證)并激活賬号。這時賬号已經成功激活正版IDEA
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
5,激活IDEA
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2,基本操作

1,登入界面
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,幫助中可以檢視快捷鍵方式(也有滑鼠墊中記錄中文IDEA快捷鍵)
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,建立工程
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

五,異常處理

什麼是異常?

異常是在程式中導緻程式中斷運作的一種指令流。

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

以上的代碼在“int temp = i / j ;”位置處産生了異常,一旦産生異常之後,異常之後的語句将不再執行了,是以現 在的程式并沒有正确的執行完畢之後就退出了。 

那麼,為了保證程式出現異常之後仍然可以正确的執行完畢,是以要采用異常的處理機制。

1,try-catch

1.1 問題引入

1,編寫代碼如下:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,運作測試
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

3,新手誤區:

容易想當然:認為所有使用者都會按照程式員的思路來操作;

容易“我認為”:使用者的需求或設計在别人看來就是合理的,程式員不是産品經理,不要擅自改動;

4,異常産生的過程

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
是以x/y這裡變成了一個new的操作
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
5,為了避免JVM接收到異常對象,可以選擇在  建立異常對象-》虛拟機  過程中攔截,這就引入了處理異常

1.2 處理異常

 1,如果要想對異常進行處理,則必須采用标準的處理格式,處理格式文法如下:
try{
    // 有可能發生異常的代碼段 
}catch(異常類型1 對象名1){ 
    // 異常的處理操作 
}catch(異常類型2 對象名2){
    // 異常的處理操作 } ... 
finally{ 
    // 異常的統一出口 
}
           
在進行異常的處理之後,在異常的處理格式中還有一個finally語句,那麼此語句将作為異常的統一出口,不管是否産生 了異常,最終都要執行此段代碼。(finally不執行情況:電腦沒電、關機、軟體關閉程式從記憶體中消失、finally之前出現exit。其餘情況finally都會執行)

1.3 finally常見面試問題

try-catch-finally 中,如果 catch 中 return 了,finally 還會執行嗎? 

答:finally中的代碼會執行 

詳解:執行流程: 

  • 1. 先計算傳回值, 并将傳回值存儲起來, 等待傳回 
  • 2. 執行finally代碼塊 
  • 3. 将之前存儲的傳回值, 傳回出去; 
需注意:
  • 1. 傳回值是在finally運算之前就确定了,并且緩存了,不管finally對該值做任何的改變,傳回的值都不 會改變 
  • 2. finally代碼中不建議包含return,因為程式會在上述的流程中提前退出,也就是說傳回的值不是try或 catch中的值
  • 3. 如果在try或catch中停止了JVM,則finally不會執行.例如停電- -, 或通過如下代碼退出 JVM:System.exit(0);
finally舉例1:(即使return,在準備傳回值與跳出函數之間,仍會執行finally中的語句)
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
finally舉例2:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
由于傳回值是引用資料類型,在return之前準備好p(将引用位址進行備份),但是finally中通過引用資料類型的位址,修改了值,是以還是顯示的最終結果會更改屬性值為28;
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
finally舉例3:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
finally舉例4:
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,處理過程如下:
  • 1、 一旦産生異常,則系統會自動産生一個異常類的執行個體化對象。 
  • 2、 那麼,此時如果異常發生在try語句,則會自動找到比對的catch語句執行,如果沒有在try語句中,則會将異 常抛出(給到調用的方法). 
  • 3、 所有的catch根據方法的參數比對異常類的執行個體化對象,如果比對成功,則表示由此catch進行處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

使用異常的效果:

1,不捕獲異常:

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,捕獲異常
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

1.4 異常的體系結構

1,異常指的是Exception , Exception類, 在Java中存在一個父類Throwable(可能的抛出) Throwable存在兩個子類: 
  • 1.Error:表示的是錯誤,是JVM發出的錯誤操作,隻能盡量避免,無法用代碼處理。(比如記憶體過小)
  • 2.Exception:一般表示所有程式中的錯誤,是以一般在程式中将進行try…catch的處理。
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,多異常捕獲的注意點: 
  • 1、 捕獲更粗的異常不能放在捕獲更細的異常之前。 
  • 2、 如果為了友善,則可以将所有的異常都使用Exception進行捕獲
3,RuntimeException:運作時異常(非受檢異常)。參數有可能引發錯誤時,發出的異常不會有提示,就直接崩潰
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

1.5 真實的異常處理場景

 1,程式異常的用途
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,運作效果
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,最終代碼
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
4,格式2(将異常合并起來,了解即可)
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
5,格式3(使用範圍更大的異常)
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

1.6 RuntimeExcepion與Exception的差別

注意觀察如下方法的源碼: 

Integer類: public static int parseInt(String text)throws NumberFormatException 

此方法抛出了異常, 但是使用時卻不需要進行try。。。catch捕獲處理,

原因: 因為NumberFormatException并不是Exception的直接子類,而是RuntimeException的子類,隻要是 RuntimeException的子類,則表示程式在操作的時候可以不必使用try…catch進行處理,如果有異常發生,則由JVM進 行處理。當然,也可以通過try catch處理。

2,throws

2.1 概念

在程式中異常的基本處理已經掌握了,但是随異常一起的還有一個稱為throws關鍵字,此關鍵字主要在方法的聲明上使 用,表示方法中不處理異常,而交給調用處處理。

格式:

傳回值 方法名稱()throws Exception{ 

}
           

2.2 什麼時候用throws/try-catch

如果是因為傳入的參數導緻異常的發生,則可以通過throws抛出異常。通常是誰調用誰處理;

如果是在此方法中調用時,可以使用try-catch處理異常,并使程式正常運作;

1,觀察下面的函數,隻有當傳入的參數錯誤時,程式才會出錯;

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,這時可以選擇,誰調用誰處理的政策;
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,如何處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

3,throw

throw關鍵字表示在程式中人為的抛出一個異常,因為從異常處理機制來看,所有的異常一旦産生之後,實際上抛出 的就是一個異常類的執行個體化對象,那麼此對象也可以由throw直接抛出。(真正應用的時候,自己造異常還是比較麻煩的,之前加判斷也可以出現相同效果。是以用的比較少)

3.1 執行個體

1,回顧以前編寫的函數
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,是以在發生異常時,需要告訴調用函數,發生了什麼問題,而不是自己默默處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,運作效果
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

4,自定義異常

編寫一個類, 繼承Exception,并重寫一參構造方法 即可完成自定義受檢異常類型。 

編寫一個類, 繼承RuntimeExcepion,并重寫一參構造方法 即可完成自定義運作時異常類型。 

例如:

class MyException extends Exception{ // 繼承Exception,表示一個自定義異常類 
    public MyException(String msg){ 
        super(msg) ; // 調用Exception中有一個參數的構造 
    } 
};
           
自定義異常可以做很多事情, 例如:
class MyException extends Exception{ 
    public MyException(String msg){ 
        super(msg) ; //在這裡給維護人員發短信或郵件, 告知程式出現了BUG。 
    } 
};
           

4.1 非受檢異常(運作時異常)

1,設計自定義的運作時異常類
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,抛出自定義的異常
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,運作效果
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

4.2 受檢異常

1,自定義受檢異常
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
2,發現飄紅
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
3,抛出異常(受檢查的異常必須明确抛出,運作時異常可以不抛出)
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
4,測試效果
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
5,解決方法
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
6,不解決,繼續執行
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

5,快遞-views/快遞-完善

此部分内容根據視訊順序截取,僅記錄過程,代碼存在問題尚未完善。

5.1 任務概述

子產品
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
任務
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

5.2 編寫代碼

2.1 views類(view包)

視圖就是視圖,隻負責展示的内容。不包含任何邏輯

1,主菜單menu

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2 快遞員菜單cMenu

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

3 使用者菜單uMenu

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

4, 快遞錄入insert

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

5,擷取快遞單号findByNumber

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

6,列印快遞資訊printExpress

有問題找産品經理,不要自己猜! 
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

7,更新快遞資訊update

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

8,删除快遞delete

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

9,列印所有快遞資訊printAll

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2.2 快遞類express(bean包)

流程:
  • 設定成員變量-》
  • 構造方法(全參/無參)-》
  • getter/setter方法-》
  • 重寫toString方法-》
  • 重寫equals方法(用于判斷兩個對象是否相同,需要考慮哪個屬性是最本質的特征) 
1,屬性及構造方法 
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2,getter/setter方法

3,toString方法

4,equals方法

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2.3 快遞對象資料操作類ExpressDao(dao包) 

1,整體描述可能需要的方法(後面把data數組改成了二維的)

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2, 成員變量(修改後的)

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

3,編寫add函數

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
【補】

4,獲得新的不重複的取件碼randCode

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

5,獲得取件碼對應的快遞對象

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

6,删除快遞對象

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

7,顯示所有快遞對象

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2.4 測試類

1,main函數

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

2,快遞員用戶端

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理
02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

3,使用者用戶端

02-面向對象一,面向對象基礎二,面向對象進階三,面向對象進階四,安裝IDEA五,異常處理

5.3 完整代碼

view類(view層)

package view;

import bean.Express;

import java.util.Scanner;

/**
 * 視圖層
 * 隻負責展示視圖 不包含其他任何邏輯
 */
public class View {
    public Scanner input = new Scanner(System.in);

    /**
     * 獲得使用者的角色選擇輸入,并進入相應的功能
     * @return 傳回功能碼 1:管理原 2:普通使用者 0:退出
     */
    public int menu(){
        System.out.println("根據提示輸入功能序号:");
        System.out.println("1,管理者");
        System.out.println("2,普通使用者");
        System.out.println("0,退出");
        String s = input.nextLine();
        int funcNum = -1;
        try{
            funcNum = Integer.parseInt(s);
        }catch (NumberFormatException e){   // 格式異常 遞歸繼續擷取功能碼
            return menu();
        }
        if(funcNum < 0 || funcNum > 2){     // 功能碼不合法
            return menu();
        }
        return funcNum;
    }

    /*
    -----------------------------------------------------------------
     */

    /**
     * 獲得管理者輸入的功能碼
     * @return 管理者輸入的合法功能碼 1:錄入 2:修改 3:删除 4:檢視所有 0:退出
     */
    public int gMenu(){
        System.out.println("根據提示輸入功能序号:");
        System.out.println("1,快遞錄入");
        System.out.println("2,快遞修改");
        System.out.println("3,快遞删除");
        System.out.println("4,檢視所有快遞");
        System.out.println("0,退出");
        String s = input.nextLine();
        int funcNum = -1;
        try{
            funcNum = Integer.parseInt(s);
        }catch (NumberFormatException e){   // 格式異常 遞歸繼續擷取功能碼
            return gMenu();
        }
        if(funcNum < 0 || funcNum > 4){     // 功能碼不合法
            return gMenu();
        }
        return funcNum;
    }

    /**
     * 1快遞員錄入資訊
     * @return 傳回包含了快遞單号和快遞公司的快遞對象
     */
    public Express insert(){
        System.out.println("請根據提示輸入快遞資訊:");
        System.out.print("請輸入快遞單号:");
        String number = input.nextLine();
        System.out.print("請輸入快遞公司:");
        String company = input.nextLine();
        Express e = new Express();
        e.setNumber(number);
        e.setCompany(company);
        return e;
    }

    /**
     * 2修改快遞資訊
     * @param e
     */
    public void update(Express e){
        System.out.print("請輸入新的快遞單号:");
        String number = input.nextLine();
        System.out.print("請輸入新的快遞公司");
        String company = input.nextLine();
        e.setNumber(number);
        e.setCompany(company);
    }

    /**
     * 3詢問是否删除
     * @return 給出快遞管理者的選擇 1:删除 2:取消
     */
    public int delete(){
        System.out.println("确認是否删除:");
        System.out.println("1,确認删除");
        System.out.println("2,取消删除");
        System.out.println("0,退出");
        String s = input.nextLine();
        int num = -1;
        try {
            num = Integer.parseInt(s);
        }catch (NumberFormatException e){
            return delete();
        }
        if(num < 0 || num > 2){
            return delete();
        }
        return num;
    }

    /**
     * 4周遊顯示所有快遞資訊
     * @param es
     */
    public void printAll(Express[][] es){
        int count = 0;
        for(int i = 0; i < 10; i++){
            for(int j = 0;j < 10; j++){
                if(es[i][j] != null) {
                    count++;
                    System.out.print("第" + (i + 1) + "排," + (j + 1) + "列, ");
                    printExpress(es[i][j]);
                }
            }
        }
        if(count == 0){
            System.out.println("暫無快遞資訊");
        }
    }

    /**
     * 提示使用者輸入快遞單号
     * @return
     */
    public String findByNumber(){
        System.out.println("請根據提示輸入快遞資訊:");
        System.out.print("請輸入需要操作的快遞單号:");
        String number = input.nextLine();
        return number;
    }

    /**
     * 顯示快遞資訊
     * @param e
     */
    public void printExpress(Express e){
        if(e == null){
            System.out.println("快遞資訊不存在");
            return;
        }
        System.out.println("快遞資訊如下:");
        System.out.println("快遞公司:" + e.getCompany() + ",快遞單号:" + e.getNumber() + ",取件碼:" + e.getCode());
    }


    /*
    -----------------------------------------------------------------
     */

    /**
     * 獲得使用者輸入的取件碼(這裡簡化,隻要取件碼相同,就算取件成功)
     * @return 使用者輸入的合法功能碼(6位)
     */
    public int uMenu(){
        System.out.println("根據提示進行取件:");
        System.out.print("請輸入取件碼:");
        String s = input.nextLine();
        int funcNum = -1;
        try{
            funcNum = Integer.parseInt(s);
        }catch (NumberFormatException e){   // 格式異常 遞歸繼續擷取功能碼
            return uMenu();
        }
        if(funcNum < 100000 || funcNum > 999999){     // 功能碼不合法
            System.out.println("輸入有誤,請重試!");
            return uMenu();
        }
        return funcNum;
    }

    public void expressExist(){
        System.out.println("此快遞單号已存在,請勿重複存儲");
    }
    public void printCode(Express e) {
        System.out.println("新快遞的取件碼為:" + e.getCode());
    }

    public void success(){
        System.out.println("操作成功!");
    }
    public void printNull(){
        System.out.println("快遞不存在,請檢查輸入");
    }

}
           

ExpressDao類(dao層)

package dao;

import bean.Express;

import java.util.Random;

public class ExpressDao {
    Express[][] data = new Express[10][];   // 二維數組表示快遞櫃
    {
        for(int i = 0; i < 10; i++){
            data[i] = new Express[10];
        }
    }
    private Random random = new Random();   // 用于生成随機數
    private int size;   // 目前存儲的快遞數目(便于判斷是否還有空位 否則在随機生成取件碼時可能陷入死循環)

    /**
     * 用于存儲快遞
     * @param e
     * @return
     */
    public boolean add(Express e){
        if(this.size >= 100){
            return false;
        }
        // 1,随機生成兩個0-9的下标
        int x = -1, y = -1;
        while (true){
            x = random.nextInt(10);
            y = random.nextInt(10);
            if(data[x][y] == null){
                // 此位置未被占用
                break;
            }
        }
        // 2,判斷取件碼是否重複(最簡單的 一個個對比)
        int code = randomCode();    // 獲得沒有重複的取件碼
        e.setCode(code);
        data[x][y] = e;
        return true;

    }
    private int randomCode(){
        while (true) {
            int code = random.nextInt(900000) + 100000; // 範圍(000000-899999)+1000000
            Express e = findByCode(code);
            if(e == null) { // 說明取件碼未重複
                return code;
            }
        }

    }

    /**
     * 快遞員根據快遞單号查詢
     * @param number
     * @return
     */
    public Express findByNumber(String number){
        Express e = new Express();
        e.setNumber(number);
        for(int i = 0; i < 10; i++){
            for(int j = 0; j < 10; j++){
                if(e.equals(data[i][j])) {  // 注意e确定不為空 但data[i][j]可能為null
                    return data[i][j];
                }
            }
        }
        return null;
    }

    /**
     * 根據取件碼查詢快遞
     * @param code 取件碼
     * @return 查詢到結果 查詢失敗傳回null
     */
    public Express findByCode(int code){
        for(int i = 0; i < 10; i++){    // 這裡确定了規格大小
            for(int j = 0; j < 10; j++){
                if(data[i][j] != null && data[i][j].getCode() == code){
                    return data[i][j];
                }
            }
        }
        return null;
    }

    /**
     * 多餘的操作 為了MVC更圓潤
     * @param oldExpress
     * @param newExpress
     */
    public void update(Express oldExpress, Express newExpress){
        delete(oldExpress);
        add(newExpress);
    }
    public void delete(Express e){
        p:for(int i = 0; i < 10; i++){
            for(int j = 0; j < 10; j++){
                if(e.equals(data[i][j])) {  // 注意e确定不為空 但data[i][j]可能為null
                    data[i][j] = null;
                    break p;
                }
            }
        }
    }
    public Express[][] findAll(){
        return data;
    }
}
           

Express類(bean層)

package bean;

import java.util.Objects;

/**
 *
 */
public class Express {
    private String number;  // 快遞單号
    private String company; // 公司
    private int code;       // 取件碼

    // 構造方法
    public Express(String number, String company, int code) {
        this.number = number;
        this.company = company;
        this.code = code;
    }

    public Express() {
    }

    // getter/setter

    public String getNumber() {
        return number;
    }

    public String getCompany() {
        return company;
    }

    public int getCode() {
        return code;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public void setCode(int code) {
        this.code = code;
    }

    // 重寫toString 方法

    @Override
    public String toString() {
        return "Express{" +
                "number='" + number + '\'' +
                ", company='" + company + '\'' +
                ", code=" + code +
                '}';
    }

    // 重寫equals方法

    /**
     * 隻要快遞單号相同就認為快遞相同
     * @param o
     * @return
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Express express = (Express) o;
        return Objects.equals(number, express.number);
    }

    @Override
    public int hashCode() {
        return Objects.hash(code);
    }
}
           

main方法(測試)

package main;

import bean.Express;
import dao.ExpressDao;
import view.View;

public class Main {
    // 初始化視圖對象
    private static View v = new View(); // 這樣可以跨方法使用
    // 初始化dao對象
    private static ExpressDao dao = new ExpressDao();
    // 1,彈出身份選擇菜單
    public static void main(String[] args) {

        m:while (true){
            int menu = v.menu();
            switch (menu){
                case 0:
                    break m;
                case 1:
                    gClient();
                    break;
                case 2:
                    uClient();
                    break;
            }
        }

    }

    private static void uClient() {
        // 1,獲得取件碼
        int code = v.uMenu();
        // 2,根據取件碼取出快遞
        Express e = dao.findByCode(code);
        if(e == null){
            v.printNull();
        }else {
            v.success();
            v.printExpress(e);
            dao.delete(e);
        }
    }

    private static void gClient() {
        while (true){
            int menu = v.gMenu();
            switch (menu){
                case 0:
                    return;
                case 1:{
                    // 1,提示輸入快遞資訊
                    Express e = v.insert();
                    // 2,此快遞是否已經存儲過
                    Express e2 = dao.findByNumber(e.getNumber());
                    // 3,存儲快遞
                    if(e2 == null){ // 未存儲過
                        dao.add(e);
                        v.printCode(e);
                    }else {         // 單号重複
                        v.expressExist();
                    }
                    break;
                }
                case 2: {// 快遞修改
                    // 1,提示輸入快遞資訊
                    String number = v.findByNumber();
                    // 2,查找資料
                    Express e1 = dao.findByNumber(number);
                    // 3,列印快遞資訊
                    if(e1 == null){
                        v.printNull();
                    }else {
                        v.printExpress(e1);
                        // 4,提示修改
                        v.update(e1);   // 這裡已經将快遞的資訊修改過了
                        dao.update(e1, e1);   // 這裡隻是為了強調 删除-修改的過程
                        v.printExpress(e1);
                    }

                    break;
                }
                case 3: {// 删除
                    // 1,輸入快遞單号
                    String number = v.findByNumber();
                    // 2,查找快遞對象
                    Express e = dao.findByNumber(number);
                    if(e == null){
                        v.printNull();
                    }else {
                        v.printExpress(e);
                        int type = v.delete();
                        if(type == 1){
                            dao.delete(e);
                        }else {
                            v.success();
                        }
                    }
                    break;
                }
                case 4:{    // 檢視所有
                    Express[][] data = dao.findAll();   // 從dao層擷取資料
                    v.printAll(data);                   // 在視圖層顯示
                    break;
                }


            }
        }

    }
}
           

繼續閱讀