### 一.定義 面向對象是:將事務高度抽象化的編程模式 將問題分解成一個個小步驟,對每個步驟進行抽象,形成對象,通過不同的對象之間調用,組合解決問題。 在進行面向對象進行編程時,要把屬性、行為等封裝成對象,然後基於這些對象及對象的能力進行業務邏輯的實現。創建一次,重覆使用 ### 二.面向對象三個 ...
一.定義
面向對象是:將事務高度抽象化的編程模式
將問題分解成一個個小步驟,對每個步驟進行抽象,形成對象,通過不同的對象之間調用,組合解決問題。
在進行面向對象進行編程時,要把屬性、行為等封裝成對象,然後基於這些對象及對象的能力進行業務邏輯的實現。創建一次,重覆使用
二.面向對象三個特性
2.1 封裝
所謂封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。
封裝是面向對象的特征之一,是對象和類概念的主要特性。簡單的說,一個類就是一個封裝了數據以及操作這些數據的代碼的邏輯實體。在一個對象內部,某些代碼或某些數據可以是私有的,不能被外界訪問。通過這種方式,對象對內部數據提供了不同級別的保護,以防止程式中無關的部分意外的改變或錯誤的使用了對象的私有部分。
封裝實現的三步驟:
1. 將屬性進行私有化private
2. 提供一個公共的set方法,用於堆屬性判斷並賦值
public void setXxx(類型 參數名){//Xxx表示某個屬性
//加入數據驗證的業務邏輯
屬性 = 參數名;
}
3. 提供一個公共的get方法,用於獲取屬性的值
public void getXxx(){
return xx;
}
2.1.1 訪問修飾符
修飾符 | 當前類 | 同一包內 | 子類 | 其他包 |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
default | Y | Y | N | N |
private | Y | N | N | N |
2.1.2 this關鍵字
this關鍵字指的是當前類
註意細節:
a. this 關鍵字可以用來訪問本類的屬性、方法、構造器
b. this 用於區分當前類的屬性和局部變數
c. 訪問成員方法的語法:this.方法名(參數列表)
d. 訪問構造器語法:this(參數列表); 註意只能在構造器中使用(即只能在構造器中訪問另外一個構造器, 必須放在第一條語句)
e. this 不能在類定義的外部使用,只能在類定義的方法中使用
2.1.3 內部類
內部類就是定義在另外一個類裡面的類。與之對應,包含內部類的類被稱為外部類。
分類:
定義在外部類局部位置(比如方法內):
1. 局部內部類(有類名)
2. 匿名內部類(沒有類名)
定義在外部類成員位置(比如方法內):
1. 成員內部類(沒有static修飾)
2. 靜態內部類(使用static修飾)
主要使用(非static關鍵字修飾的內部類):
1. 內部類提供了更好的封裝,可以把內部類隱藏在外部類之內,不允許同一個包中的其他類訪問該類。
2. 內部類的方法可以直接訪問外部類的所有數據,包括私有的數據。
3. 內部類所實現的功能使用外部類同樣可以實現,只是有時使用內部類更方便
4. 外部類訪問內部類成員方式:創建對象再訪問,但需在作用域內實現
5. 如果外部類和局部類的成員重名時,遵循就近原則,如果想訪問外部類的成員,可以使用this關鍵字去訪問
2.2 繼承
繼承是指這樣一種能力:它可以使用現有類的所有功能,併在無需重新編寫原來的類的情況下對這些功能進行擴展。
通過繼承創建的新類稱為“子類”或“派生類”,被繼承的類稱為“基類”、“父類”或“超類”。繼承的過程,就是從一般到特殊的過程。
繼承概念的實現方式有二類:實現繼承與介面繼承。實現繼承是指直接使用基類的屬性和方法而無需額外編碼的能力;介面繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現的能力。
2.2.1 方法的重寫
方法重寫就是子類的一個方法和父類一個方法名稱、返回類型、參數一樣,子類的方法覆蓋了父類的方法,那我們就說子類 重寫了父類的方法。
重寫條件:
- 參數列表必須完全與被重寫方法的相同;
- 返回類型必須完全與被重寫方法的返回類型相同;
- 訪問級別的限制性一定不能比被重寫方法的強;
- 訪問級別的限制性可以比被重寫方法的弱;
註意細節:
a. 子類的方法的形參列表、方法列表,要和父類方法的形參列表,方法名稱完全一樣
b. 子類方法的返回類型和父類方法返回類型一樣,或者是父類返回類型的父類
c. 子類方法不能縮小父類方法的訪問許可權
d. 重寫方法一定不能拋出新的檢查異常或比被重寫的方法聲明的檢查異常更廣泛的檢查異常。
e. 重寫的方法能夠拋出更少或更有限的異常(也就是說,被重寫的方法聲明瞭異常,但重寫的方法可以什麼也不聲明)。
f. 不能重寫被標示為 final 的方法。
g. 如果不能繼承一個方法,則不能重寫這個方法。
2.2.2 方法的重載
Java同一個類中,多個同名方法的存在,但要求參數類型或者個數順序不一致任意,互相稱為重載函數或方法重載。
重載條件:
- 被重載的方法必須改變參數列表;
- 被重載的方法可以改變返回類型;
- 被重載的方法可以改變訪問修飾符;
- 被重載的方法可以聲明新的或更廣的檢查異常;
- 方法能夠在同一個類中或者在一個子類中被重載
2.2.3 繼承的初始化順序
父類對象屬性初始化---->父類對象構造方法---->子類對象屬性初始化--->子類對象構造方法
2.2.4 final關鍵字
final可以修飾類、屬性、方法和局部變數
使用情景:
- 當不希望類被繼承,可以用final修飾
- 當不希望父類的某個方法被子類重載/重寫時,可以用final關鍵字修飾
- 當不希望類的某個屬性的值被修改,可以用final修飾
- 當不希望某個局部變數被修改,可以使用final修飾
註意細節:
- final修飾的屬性又叫常量,一般用XX_XX_XX 來命名
- final修飾的屬性再定義時,必須賦初始值,並且以後不能修改,賦值可以在以下位置任選:
定義時:如public final int MAX_sum=8;
在構造器中
在代碼塊中 - 如果final修飾的屬性是靜態的,則初始化的位置只能是
定義時或在靜態代碼塊,不能在構造器中賦值 - final不能繼承,但是可以實例化對象
- 如果類不是final類,但是含有final方法,則該方法雖然不能重寫,但是可以被繼承
- 一般來說,如果一個類是final類,就沒有必要再將方法修飾成final方法
- final不能修飾構造器
- final和static往往搭配使用,效率更高,不會導致類載入,底層編譯器做了優化處理
2.2.5 super關鍵字
super代表父類的引用,用於訪問父類的屬性、方法、構造器
基本語法:
- 訪問父類的屬性,但不能訪問父類的private屬性。例:super.屬性名
- 訪問父類的方法,不能訪問父類的private方法。例:super.方法名(參數列表)
- 訪問父類的構造器:super(參數列表),只能放在構造器的第一句,只能出現一句
細節:
- 調用父類的構造器分工明確。父類屬性由父類初始化,子類屬性子類初始化
- 當子類中有和父類的成員重名時,為了訪問父類的成員,必須使用super.如果沒有重名,使用super、this、直接訪問是一樣的效果
- super的訪問不限於直接父類,如果爺爺類和本類中有同名的成員,也可以使用super去訪問爺爺類的成員,如果多個基類都有同名的成員,使用
super訪問遵循就近原則。 - 如果查詢到父類super成員是private私有的,爺爺類super是公共的,也會查詢父類的對象,直接報錯,而不會看爺爺類的成員
- 子類的構造器預設有一個隱藏的super無參構造器
2.3 多態
所謂多態就是指一個類實例的相同操作在不同對象有不同解釋,產生不同的執行結果。多態機制使具有不同內部結構的對象可以共用相同的外部介面。這意味著,雖然針對不同對象的具體操作不同,但通過一個公共的類,它們(那些操作)可以通過相同的方式予以調用。
最常見的多態就是將子類傳入父類參數中,運行時調用父類方法時通過傳入的子類決定具體的內部結構或行為
多態的概念比較簡單,就是同一操作作用於不同的對象,可以有不同的解釋,產生不同的執行結果。
如果按照這個概念來定義的話,那麼多態應該是一種運行期的狀態
多態的必要條件
為了實現運行期的多態,或者說是動態綁定,需要滿足三個條件。即有類繼承或者介面實現、子類要重寫父類的方法、父類的引用指向子類的對象
2.3.1 抽象類,介面
詳細請看這一篇文章
2.3.2 介面和匿名內部類使用
public class test_1 {
public static void main(String[] args) {
System.out.println("歡迎來到 寵物商店");
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入你要領養的寵物的名字");
String next = scanner.next();
System.out.println("請輸入你要領養的寵物類型:1.狗狗\t2.企鵝\t3.貓");
int i = scanner.nextInt();
Pet pet = new Pet(next,100,0);
switch (i){
case 1:
System.out.println("請選擇品種:1.拉布拉多\t2.肯達爾");
int next1 = scanner.nextInt();
String next2= (next1 == 1 ? "拉布拉多" : "肯達爾");
System.out.println(pet);
pet.show(new IA() {
@Override
public void aic() {
System.out.println("品種是"+next2);
}
@Override
public void aii() {
System.out.println(next2+"吃飽了,健康值增加5");
pet.setHealth(-5);
}
public void play() {
pet.setHealth(5);
pet.setLove(5);
System.out.println(next2+"正在亂跑");
}
});
break;
case 2:
System.out.println("請選擇性別:1.Q仔\t2.Q崽");
int next3 = scanner.nextInt();
String next4= (next3 == 1 ? "Q仔" : "Q崽");
System.out.println(pet);
pet.show(new IA() {
@Override
public void aic() {
System.out.println("名字是是"+next);
}
public void aii() {
System.out.println(next4+"吃飽了,健康值增加3");
pet.setHealth(-3);
}
@Override
public void play() {
pet.setHealth(5);
pet.setLove(5);
System.out.println(next4+"正在閑逛");
}
});
break;
case 3:
System.out.println("請選擇性別:1.C仔\t2.C崽");
int next5 = scanner.nextInt();
String next6= (next5 == 1 ? "Q仔" : "Q崽");
System.out.println(pet);
pet.show(new IA() {
@Override
public void aic() {
System.out.println("名字是是"+next6);
}
public void aii() {
System.out.println(next6+"吃飽了,健康值增加3");
pet.setHealth(-3);
}
@Override
public void play() {
pet.setHealth(5);
pet.setLove(5);
System.out.println(next+"正在舔毛");
}
});
break;
default:
System.out.println("對不起沒有這種類型寵物");
}
}
}
public class Pet {
private final String name;
int health;
public void setHealth(int health) {
this.health -=health;
}
public void setLove(int love) {
this.love += love;
}
private int love;
public Pet(String name, int health, int love) {
this.name = name;
this.health = health;
this.love = love;
}
@Override
public String toString() {
return
"name='" + name + '\'' +
", health=" + health +
", love=" + love ;
}
public void show(IA ia){
ia.aic();
ia.aii();
ia.play();
}
}
interface IA extends IC{
public void aic();
public void play();
}
interface IC{
public void aii();
}