day04面向物件、static、繼承
面向物件程式設計OOP
1、概念
面向物件最重要的概念是:類和物件。
- 類——是相同事物共同特徵的描述,類並不是具體的
- 物件——是真實存在的具體例項
- 類只有一個,物件可以很多個,這樣就可以實現描述萬千事物了
- 先有類才有物件
定義類
-
格式:
修飾符 class 類名{
}
-
類名首字母大寫
-
一個Java檔案中可以定義多個類。但是隻能有一個類是用public修飾。
-
public修飾的類名必須成為Java程式碼的檔名稱。 實際開發的規範:一個Java程式碼檔案只定義一個類
構造器
-
作用:呼叫構造器得到一個物件
-
格式:
修飾符 類名 (形參列表){
//執行程式碼
}
-
注意事項:
如果一個類沒有申明任何構造器,預設會自動一個無引數構造器
如果一個類自己定義了有引數構造器,那麼預設的無引數構造器就消失了。如果此時還想要無引數構造器,就必須自定義無引數構造器
this關鍵字
- this代表當前物件的引用
- 可以出現在構造器和方法中
- 在構造器中表示正在初始化的物件
- 在方法中表示呼叫方法的物件
- 可以訪問物件的成員變數,可以區分成員變數是區域性的還是物件中的
封裝
- 面向物件的三大特徵:封裝、繼承、多型
- 成員變數一般私有,方法一般暴露,一般要給私有的成員變數一套getter/setter方法進行取值/賦值
- 封裝提高了程式碼安全性和元件化
2、static關鍵字
-
static == 靜態 == 修飾的成員(方法或變數)屬於類本身
-
按照有無static修飾,成員變數和方法可以分為:
成員變數:
(1)靜態成員變數(類變數):有static修飾的成員變數稱為靜態成員變數也叫類變數,屬於類本身的,直接用類名訪問,也可用類的物件訪問但不建議。
(2)例項成員變數:無static修飾的成員變數稱為例項成員變數,屬於類的每個物件的,必須用類的物件來訪問
成員方法:
(1)靜態方法:有static修飾的成員方法稱為靜態方法也叫類方法,屬於類本身的,直接用類名訪問
(2)例項方法:無static修飾的成員方法稱為例項方法,屬於類的每個物件的,必須用類的物件來訪問
3、成員變數和成員方法的訪問
靜態成員變數訪問:
- 類名.靜態成員變數
- 物件.靜態成員變數(不建議)
例項成員變數訪問:
-
先建立物件
-
物件.例項成員變數
靜態方法訪問:
- 類名.靜態方法
- 物件.靜態方法(不建議)
例項方法訪問:
- 先建立物件
- 物件.例項方法
拓展面試題:
(1)靜態方法中是否可以直接訪問靜態方法? 可以的,都屬於類可以直接訪問的
(2)靜態方法中是否可以直接訪問例項方法? 不可以的,例項方法屬於物件必須用物件訪問
(3)靜態方法中是否可以直接訪問靜態成員變數? 可以的,都屬於類,可以直接訪問
(4)靜態方法中是否可以直接訪問例項成員變數? 不可以的,例項成員變數屬於物件必須用物件訪問
----------------------------------------------------------------
(1)例項方法中是否可以直接訪問靜態方法? 可以的,靜態方法可以被共享
(2)例項方法中是否可以直接訪問例項方法? 可以的,因為他們都屬於物件,在同一個物件中是可以訪問的
(3)例項方法中是否可以直接訪問靜態成員變數? 可以的,靜態成員變數可以被共享
(4)例項方法中是否可以直接訪問例項成員變數? 可以的,因為都屬於物件,可以訪問
4、繼承
①概述
-
繼承(is a)是子類到父類的一種關係。被繼承的類:父類;繼承父類的類:子類
-
格式:
子類 extends 父類{
}
-
作用:可以提高程式碼的複用——相同程式碼可以定義在父類中子類繼承父類就可直接使用
-
繼承中子類會比父類更加強大,因為子類出了父類的屬性和行為還能自定義其他功能
②子類不能繼承的內容
- 確定觀點:子類無法繼承父類的構造器,子類自己本身也有構造器無需繼承。
- 子類可以繼承父類的私有成員(變數和方法),但是無法直接訪問
- 子類不能繼承父類的靜態成員(變數和方法),父類只是共享給子類訪問,並非繼承
③繼承後成員變數的特點
-
就近原則:子類有同名變數就優先找子類,否則找父類,父類也沒有就報錯
public class Demo { public static void main(String[] args) { Student student = new Student(); System.out.println(student.name); // 找子類 CC System.out.println(student.name1); // 找父類 BB // System.out.println(student.name2); // 子類父類都沒有就報錯 } } // 父類 class People{ public String name = "AA"; public String name1 = "BB"; } // 子類 class Student extends People{ public String name = "CC"; }
-
如果子類要訪問父類的成員變數,且有相同的成員變數,會優先使用子類的
-
如果子類一定要訪問父類的成員變數,需要使用super關鍵字
public class Demo02 { public static void main(String[] args) { Student student = new Student(); student.showName(); } } class People{ public String name = "人類"; } class Student extends People{ public String name = "學生"; public void showName(){ String name = "區域性名稱"; System.out.println(name); // 區域性變數 System.out.println(this.name); // 子類的 學生 System.out.println(super.name); // 父類的 人類 } }
④繼承後成員方法的特點
- 同成員變數,滿足就近原則
⑤方法重寫
- 概念:子類繼承了父類得到了父類的方法,但是子類不滿足父類的方法就自己重寫一個同樣的方法來覆蓋父類的方法
- 要求:
- 子類重寫方法的名稱和形參列表必須與父類被重寫的方法完全一致
- 子類重寫方法的訪問許可權應該與父類一樣或更大
- 若父類方法丟擲了異常,則子類丟擲的異常應該與父類一樣或更小
- 方法重寫的返回值型別應與父類返回值型別一樣或類型範圍更小
- 校驗註解:@Override 加上註解後必須正確重寫父類方法,否則報錯
⑥繼承後構造器特點
-
繼承後,子類的全部構造器一定會先呼叫父類的無參構造器再執行自己的
-
因為子類構造器第一行有一行隱藏程式碼super(),呼叫父類的無參構造器
-
先有爹才有兒
public class Demo { public static void main(String[] args) { Cat cat = new Cat(); Cat cat1 = new Cat("喵喵"); } } //父類 class Animal{ public Animal(){ System.out.println("父類的無引數構造器被執行"); } } //子類 class Cat extends Animal{ public Cat(){ //super(); // 預設存在,呼叫父類的無引數構造器。 System.out.println("子類的無引數構造器被執行"); } public Cat(String name){ //super(); // 預設存在,呼叫父類的無引數構造器。 System.out.println("子類的有引數構造器被執行"); } } /* 輸出結果: 父類的無引數構造器被執行 子類的無引數構造器被執行 父類的無引數構造器被執行 子類的有引數構造器被執行 */
⑦super呼叫父類有參構造器
-
子類會在構造器的第一行預設執行super();呼叫父類無參構造器
-
如果需要呼叫父類有參構造器需要匹配引數super(引數匹配);
-
把賦值的資料從子類傳到父類構造器中去初始化
-
減少程式碼冗餘,提高程式碼複用
public class Demo { public static void main(String[] args) { Dog dog = new Dog("泰迪", 15); System.out.println(dog.getName()); System.out.println(dog.getAge()); } } //子類 class Dog extends Animal{ public Dog(String name , int age){ super(name , age); } } // 父類。 class Animal{ private String name ; private int age ; public Animal() { } public Animal(String name, int age) { this.name = name; this.age = age; } //getter/setter方法 }
⑧this和super對比
-
this代表當前類物件(子類)
super代表父類物件引用
-
this用在本類中訪問本類物件成員:
this.本類成員變數 (可省)
this.本類成員方法 (可省)
this(…) 在本類構造器中訪問本類其他構造器,可以借用兄弟構造器來賦預設值。程式碼如下
super用在本類中訪問父類物件成員:
super.父類成員變數
super.父類成員方法
super(…) 在本類構造器中訪問父類其他構造器
-
super(…);和this(…);不能同時出現在構造器中,因為都必須在第一行
public class ThisDemo {
public static void main(String[] args) {
// 希望不給學校資訊,預設就是北大的
Student s3 = new Student("AA",25 );
System.out.println(s3.getName());
System.out.println(s3.getAge());
System.out.println(s3.getSchoolName());
Student s5 = new Student("BB",24 , "清華大學" );
System.out.println(s5.getName());
System.out.println(s5.getAge());
System.out.println(s5.getSchoolName());
}
}
class Student{
private String name ;
private int age ;
private String schoolName ;
//無參構造器
public Student() {
}
//this(...)訪問本類的其他構造器
public Student(String name , int age){
// this(...)借用兄弟構造器功能
this(name ,age ,"北京大學");
}
//有參構造器
public Student(String name, int age, String schoolName) {
this.name = name;
this.age = age;
this.schoolName = schoolName;
}
//getter/setter方法
}
⑨繼承的特點
-
Java是單繼承的:一個類只能繼承一個直接父類
——假如Java可以繼承多個類則出現了類的二義性
-
但是一個類可以間接繼承多個父類,多層繼承
-
一個父類可以有多個子類
-
Java中祖宗類是Object類,一個類要麼預設繼承了Object類要麼間接繼承了Object類