天天看點

Java程式員養成之路-基礎知識4

面向對象

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

作用:幫助檢查重寫方法的方法聲明的正确性。