一、封裝
面向對象編程語言是對客觀世界的模擬,客觀世界裏成員變量都是隱藏在對象內部的,外界無法直接操作和修改。封裝可以被認爲是一個保護屏障,防止該類的代碼和數據被其他類隨意訪問。要訪問該類的數據,必須通過指定的方式。適當的封裝可以讓代碼更容易理解與維護,也加強了代碼的安全性。
將屬性隱藏起來,提供公共方法訪問某個屬性。
1、private關鍵字
- private是一個權限修飾符,代表最小權限。
- 可以修飾成員變量和成員方法。
- 被private修飾後的成員變量和成員方法,只在本類中才能訪問。
2、this關鍵字
this代表所在類的當前對象的引用(地址值),即對象自己的引用。
方法被哪個對象調用,方法中的this就代表那個對象。誰在調用,this就代表誰。
this使用格式
this.成員變量名;
使用 this
修飾方法中的變量,解決成員變量被隱藏的問題,代碼如下:
public class Student {
private String name;
public void setName(String name) {
//name = name;
this.name = name;
}
public String getName() {
return name;
}
}
3、構造方法
當一個對象被創建時候,構造方法用來初始化該對象,給對象的成員變量賦初始值。
無論你與否自定義構造方法,所有的類都有構造方法,因爲Java自動提供了一個無參數構造方法,一旦自己定義了構造方法,Java自動提供的默認無參數構造方法就會失效。
構造方法的定義格式
修飾符 構造方法名(參數列表){
// 方法體
}
構造方法的寫法上,方法名與它所在的類名相同。它沒有返回值,所以不需要返回值類型,甚至不需要void。使用構造方法後,代碼如下:
public class Student {
private String name;
private int age;
// 無參數構造方法
public Student() {}
// 有參數構造方法
public Student(String name,int age) {
this.name = name;
this.age = age;
}
}
注意事項:
- 如果你不提供構造方法,系統會給出無參數構造方法。
- 如果你提供了構造方法,系統將不再提供無參數構造方法。
- 構造方法是可以重載的,既可以定義參數,也可以不定義參數。
4、標準代碼
JavaBean
是 Java語言編寫類的一種標準規範。符合JavaBean
的類,要求類必須是具體的和公共的,並且具有無參數的構造方法,提供用來操作成員變量的set
和get
方法。
public class ClassName{
//成員變量
//構造方法
//無參構造方法【必須】
//有參構造方法【建議】
//成員方法
//getXxx()
//setXxx()
}
編寫符合JavaBean
規範的類,以學生類爲例,標準代碼如下:
public class Student {
//成員變量
private String name;
private int age;
//構造方法
public Student() {}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
//成員方法
publicvoid setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
publicvoid setAge(int age) {
this.age = age;
}
publicint getAge() {
return age;
}
}
測試類,代碼如下:
public class TestStudent {
public static void main(String[] args) {
//無參構造使用
Student s= new Student();
s.setName("柳巖");
s.setAge(18);
System.out.println(s.getName()+"---"+s.getAge());
//帶參構造使用
Student s2= new Student("趙麗穎",18);
System.out.println(s2.getName()+"---"+s2.getAge());
}
}
二、繼承
1、概述
多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行爲,只要繼承那一個類即可。如圖所示:
其中,多個類可以稱爲子類,單獨那一個類稱爲父類、超類(superclass)或者基類。
繼承描述的是事物之間的所屬關係。例如,圖中兔子屬於食草動物,食草動物屬於動物。可見,父類更通用,子類更具體。我們通過繼承,可以使多種事物之間形成一種關係體系。
2、定義
繼承:就是子類繼承父類的屬性和行爲,使得子類對象具有與父類相同的屬性、相同的行爲。子類可以直接訪問父類中的非私有的屬性和行爲。
優點:
- 提高代碼的複用性。
- 類與類之間產生了關係,是多態的前提。
3、格式
通過 extends
關鍵字,可以聲明一個子類繼承另外一個父類,定義格式如下:
class 父類 {
...
}
class 子類 extends 父類 {
...
}
4、繼承後的特點
成員變量:
子父類中出現了同名的成員變量時,在子類中需要訪問父類中非私有成員變量時,需要使用super
關鍵字,修飾父類成員變量。
構造方法:
當類之間產生了關係,其中各類中的構造方法,又產生了哪些影響呢?
首先我們要回憶兩個事情,構造方法的定義格式和作用。
- 構造方法的名字是與類名一致的。所以子類是無法繼承父類構造方法的。
- 構造方法的作用是初始化成員變量的。所以子類的初始化過程中,必須先執行父類的初始化動作。子類的構造方法中默認有一個
super()
,表示調用父類的構造方法,父類成員變量初始化後,纔可以給子類使用。
成員方法:
成員方法不重名
如果子類父類中出現不重名的成員方法,這時的調用是沒有影響的。
成員方法重名——重寫(Override)
如果子類父類中出現重名的成員方法,需要進行方法重寫(Override)。
- 方法重寫 :子類中出現與父類一模一樣的方法時,需要重寫父類的方法。
子類可以根據需要,定義特定於自己的行爲。既沿襲了父類的功能名稱,又根據子類的需要重新實現父類方法,從而進行擴展增強。
class Phone {
public void showNum(){
System.out.println("來電顯示號碼");
}
}
extends:
//智能手機類
class NewPhone extends Phone {
//重寫父類的來電顯示號碼功能,並增加自己的顯示姓名和圖片功能
public void showNum(){
//調用父類已經存在的功能使用super
super.showNum();
//增加自己特有顯示姓名和圖片功能
System.out.println("顯示來電姓名");
System.out.println("顯示頭像");
}
}
Test:
public class ExtendsDemo06 {
public static void main(String[] args) {
// 創建子類對象
NewPhone np = new NewPhone();
// 調用子類重寫的方法
np.showNum();
}
}
注意事項:
- 子類方法覆蓋父類方法,必須要保證權限大於等於父類權限。
- 子類方法覆蓋父類方法,返回值類型、函數名和參數列表都要一模一樣。
- 子類方法覆蓋父類方法,子類的返回值類型要是父類返回值類型的子類。
5、super和this區別
父類空間優先於子類對象產生
在每次創建子類對象時,先初始化父類空間,再創建其子類對象本身。目的在於子類對象中包含了其對應的父類空間,便可以包含其父類的成員,如果父類成員非private修飾,則子類可以隨意使用父類成員。代碼體現在子類的構造方法調用時,一定先調用父類的構造方法。理解圖解如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gggegzp7-1592739295232)(img/2.jpg)]
super和this的含義
-
super :代表父類的存儲空間標識(可以理解爲父親的引用)。
-
this :代表當前對象的引用(誰調用就代表誰)。
特點:
- 子類的每個構造方法中均有默認的super(),調用父類的空參構造。
- 手動調用父類構造會覆蓋默認的super()。
- super() 和 this() 都必須是在構造方法的第一行,所以不能同時出現。
6、繼承的特點
Java只支持單繼承。
三、多態
1、概述
- 多態: 是指同一行爲,具有多個不同表現形式。
前提:
- 繼承或者實現【二選一】
- 方法的重寫【意義體現:不重寫,無意義】
- 父類引用指向子類對象【格式體現】
2、格式
多態體現的格式:
父類類型 變量名 = new 子類對象;
變量名.方法名();
代碼:
Fu f = new Zi();
f.method();
當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤;
如果有,執行的是子類重寫後方法。
3、多態的應用
實際開發的過程中,父類類型作爲方法形式參數,傳遞子類對象給方法,進行方法的調用,更能體現出多態的擴展性與便利。
定義父類:
public abstract class Animal {
public abstract void eat();
}
定義子類:
class Cat extends Animal {
public void eat() {
System.out.println("喫魚");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("喫骨頭");
}
}
定義測試類:
public class Test {
public static void main(String[] args) {
// 多態形式,創建對象
Cat c = new Cat();
Dog d = new Dog();
showAnimalEat(c);
showAnimalEat(d);
}
public static void showAnimalEat (Animal a){
a.eat();
}
}
由於多態特性的支持,showAnimalEat方法的Animal類型,是Cat和Dog的父類類型,父類類型接收子類對象,當然可以把Cat對象和Dog對象,傳遞給方法。
多態的好處,可以使程序編寫的更簡單,並有良好的擴展。
4、向上轉型和向下轉型
- 向上轉型:多態本身是子類類型向父類類型向上轉換的過程,這個過程是默認的。
當父類引用指向一個子類對象時。
父類類型 變量名 = new 子類類型();
如:Animal a = new Cat();
- 向下轉型:父類類型向子類類型向下轉換的過程,這個過程是強制的。
一個已經向上轉型的子類對象,將父類引用轉爲子類引用,可以使用強制類型轉換的格式。
子類類型 變量名 = (子類類型) 父類變量名;
如:Cat c =(Cat) a;
5、ClassCastException異常
代碼能通過編譯,但是運行時,卻報出了 ClassCastException
,類型轉換異常!這是因爲,明明創建了Cat類型對象,運行時,當然不能轉換成Dog對象的。這兩個類型並沒有任何繼承關係,不符合類型轉換的定義。
爲了避免ClassCastException的發生,Java提供了 instanceof
關鍵字,給引用變量做類型的校驗。
變量名 instanceof 數據類型
如果變量屬於該數據類型,返回true。
如果變量不屬於該數據類型,返回false。
所以,轉換前,我們最好先做一個判斷,代碼如下:
public class Test {
public static void main(String[] args) {
// 向上轉型
Animal a = new Cat();
a.eat(); // 調用的是 Cat 的 eat
// 向下轉型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 調用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 調用的是 Dog 的 watchHouse
}
}
}
6、interface作爲參數傳遞
當接口作爲方法的參數時,需要傳遞它的子類對象。
- 接口作爲參數時,傳遞它的子類對象。
- 接口作爲返回值類型時,返回它的子類對象。
定義方法:
public static void printEvenNum(List list) {
// 遍歷集合list
for (int i = 0; i < list.size(); i++) {
Object num = list.get(i);
System.out.println(num);
}
}
調用方法:
public class Test {
public static void main(String[] args) {
// 創建ArrayList集合,並添加數字
ArrayList<Integer> srcList = new ArrayList<>();
srcList.add(10);
//調用方法,傳遞參數
printEvenNum(srcList);
}
}