面向對象
1.面向對象概述
面向對象是相對于面向過程而言的,是以,了解面向對象,先要了解面向過程是什麼。
面向過程(Procedure Oriented)就是通過分析要解決的問題,并拆分成若幹個步驟,然後按照這些步驟依次進行,比如做一道菜,那就需要依次進行買菜、洗菜、切菜、炒菜、裝盤這些步驟,這就是面向過程的思想。
面向對象(Object Oriented,OO)則是把構成問題的事務按照一定規則劃分為多個獨立的對象,建立對象的目的不是為了完成一個步驟,而是為了描述某個事物在整個解決問題的步驟中的行為。
面向對象程式設計(Procedure Oriented Programming,OOP)的本質:以類的方式組織代碼,以對象的組織封裝資料。
2.面向對象特性
2.1 封裝
(1)封裝是面向對象的核心思想,将對象的屬性和行為封裝起來,不需要讓外界知道具體實作細節。比如玩手機,我們并不需要知道手機内部到底是怎麼運作的,就可以使用手機。
(2)程式的設計要追求“高内聚,低耦合”。高内聚就是類的内部資料操作細節自己完成,不允許外部幹涉;低耦合就是僅暴露少量的方法給外部使用。
(3)封裝的優點:
- 良好的封裝可以降低耦合度。
- 保護資料,可以對成員變量進行更精确的控制。
- 隐藏代碼,實作細節。
- 增強系統的可維護性。
public class Student {
// 使用private對變量進行修飾,達到封裝的目的
// 屬性私有
private String name; // 姓名
private int age; // 年齡
private char sex; // 性别
// 使用public對方法進行修飾,以便外部能夠通過使用get、set方法對屬性進行操作
// 方法公有
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
// 對setAge()方法添加判斷條件,外部看不到
public void setAge(int age) {
if (age < 120 && age > 0) {
this.age = age;
}else {
age = 0;
}
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
2.2 繼承
(1)繼承主要描述的是類與類之間的關系,繼承可以在無需重新編寫原有類的情況下,對原有類的功能進行擴充。
(2)繼承的關鍵字是extends。Java中類隻有單繼承,沒有多繼承,即一個子類(派生類)有且僅能繼承一個父類(基類、超類)。
/*動物類(父類)*/
public class Animal {
private String name;
private double weight;
public void eat() {
System.out.println("吃飯ing");
}
}
/*狗類(子類)*/
public class Dog extends Animal {
public void run() {
System.out.println("跑步ing");
}
}
/*測試類*/
public class Test {
public static void main(String[] args) {
// 建立一個對象
Dog dog = new Dog();
// 調用動物類的eat()方法
dog.eat();
// 調用狗類的run()方法
dog.run();
}
}
/*
輸出結果:
吃飯ing
跑步ing
*/
2.3 多态
(1)多态指的是在一個類中定義的屬性和方法被其他類繼承後,當把子類對象直接指派給父類引用變量時,相同引用類型的變量調用同一個方法所呈現出的多種不同行為特性。
(2)多态的三個前提
- 存在繼承或實作關系
- 子類重寫父類方法
- 父類引用指向子類對象(如Father father = new Son();)
(3)好處和弊端
- 好處:提高程式的擴充性。定義方法時,使用父類型作為參數,以後使用的時候,就可以使用不同具體的子類型參與操作。
- 弊端:不能使用子類特有方法。
/*動物類*/
public class Animal {
public int age = 2;
public void eat() {
System.out.println("吃東西");
}
}
// 子類(狗類)繼承父類(動物類)
public class Dog extends Animal {
public int age = 3;
public int weight = 20;
// 重寫父類(動物類)方法
@Override
public void eat() {
System.out.println("狗吃狗糧");
}
// 子類特有方法
public void lookHouse() {
System.out.println("狗狗看家");
}
}
/*測試類*/
public class Test {
public static void main(String[] args) {
/*
向上轉型:
從子類到父類,父類引用指向子類對象
*/
Animal dog = new Dog();
// 多态是方法的多态,屬性沒有多态性,是以下面輸出為:2
System.out.println(dog.age);
// 子類重寫父類方法,執行子類方法,是以下面輸出為:狗吃狗糧
dog.eat();
// 不能調用子類特有的方法
dog.lookHouse(); // 報錯:Cannot resolve method 'lookHouse' in 'Animal'
/*
向下轉型:
從父類到子類,父類引用轉為子類對象
*/
((Dog)dog).lookHouse();
}
/*
運作結果:
2
狗吃狗糧
狗狗看家
*/
編譯看左邊,執行看右邊:
父類變量引用指向子類對象時,該變量的成員變量和靜态方法和父類保持一緻,而對于非靜态方法,編譯時與父類一緻,運作時則與子類一緻。
3.類與對象的關系
類是對某一類事物的抽象描述,包括屬性(成員變量)和行為(成員方法)。比如人,有身高、體重等屬性,也有吃、喝、玩等行為,将這些共同的屬性和行為提取出來就可以形成一個類,是以一個類可以簡單了解為就是一個模闆。
對象用于表示現實中該類事物的個體,是類的執行個體化、具體化,并且一個類可以對應多個對象。比如貓貓、狗狗、雞雞、鴨鴨等就是動物類的對象。當然,貓又分為黑貓、白貓、大貓、小貓,是以,貓也可以單獨作為一個類。
類是抽象的,對象是具體的
public class Demo {
public static void main(String[] args) {
// 通過new建立一個對象
Animal animal = new Animal();
// 給該對象指派
animal.name = "小一";
animal.weight = 20.20;
// 調用該對象的方法
animal.eat(); // 小一正在吃飯!現在是20.2kg。
}
}
// 定義一個動物類
class Animal {
// 定義兩個屬性
String name;
double weight;
// 定義一個行為(方法)
public void eat() {
System.out.println(name + "正在吃飯!現在是" + weight + "kg。");
}
}
4.構造方法
構造方法,也稱為構造器,是一種專門用來建立對象的方法,其功能主要是完成對象的初始化,與其他方法一樣也可以重載。
public class Person {
String name;
int age;
// 無參構造方法
public Person() {
}
// 有參構造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
注意:
- 構造方法必須和所在類的名字一模一樣。
- 構造方法不需要寫傳回類型,也不能寫void。
- 如果沒有編寫任何構造方法,編譯器會自動建立一個無參構造方法(可以通過IDEA反編譯檢視.class檔案)。
- 如果編寫了至少一個構造方法,那編譯器就不會自動建立無參構造方法,若需要使用無參構造方法,則需要手動添加。
拓展1:值傳遞和引用傳遞
值傳遞:指在調用函數時将實際參數複制一份傳遞給函數,這樣在函數中對參數進行修改,将不會影響到實際參數。
/*值傳遞*/
public class Demo {
public static void main(String[] args) {
int num = 2;
System.out.println(num); // 輸出結果:2
change(num); // 并沒有改變實際參數
System.out.println(num); // 輸出結果:2
}
// 無傳回值
private static void change(int a) {
a = 20;
System.out.println(a); // 輸出結果:20
}
}
引用傳遞:指在調用函數時将實際參數的位址傳遞(而非值)到函數中,這樣在函數中對參數所進行的修改,将影響到實際參數。
/*引用傳遞*/
public class Demo {
public static void main(String[] args) {
Student student = new Student();
// 輸出結果:null今年0歲!
System.out.println(student.name + "今年" + student.age + "歲了!");
change(student);
// 輸出結果:小一今年18歲!
System.out.println(student.name + "今年" + student.age + "歲了!");
}
// 無傳回值
private static void change(Student student) {
student.name = "小一";
student.age = 18;
}
}
// 定義Student類
class Student {
String name;
int age;
}
拓展2:方法重寫
方法重寫用于繼承關系中,即子類重寫父類的方法(名稱相同,方法體不同)。當子類需要父類的功能,而子類又有自己的特有内容時,就可以通過方法重寫實作,這樣,子類即繼承了父類的功能,又有自己的特有内容。
/*人類*/
public class Person {
// 父類方法
public void sleep (String name) {
System.out.println(name + "在睡覺!");
}
}
/*學生類*/
public class Student extends Person{
// 重寫父類方法
public void sleep(String name) {
System.out.println(name + "在玩手機");
// 繼承父類方法
super.sleep(name);
}
}
/*測試類*/
public class Test {
public static void main(String[] args) {
// 建立對象,調用方法
Person person = new Person();
person.sleep("小一");
System.out.println("-------------");
Student student = new Student();
student.sleep("小二");
}
/*
運作結果:
小一在睡覺!
-------------
小二在玩手機
小二在睡覺!
*/
注意事項:
- 方法名必須相同
- 參數清單必須相同
- 修飾符的權限範圍隻增不減(public>protected>default>private)
- 被static、final、private修飾的方法不能被重寫
注解:@Override
作用:幫助檢查重寫方法的方法聲明的正确性。