06- 面向對象之封裝 繼承

面向對象有三大特性 : 封裝 繼承 多態

封裝

程序設計中遇到的問題

public class Student {
    String name;
    int age;
    String sex;
    String birthday;
}

測試類中引用

Student stu = new Student();
stu.name = "於志強";
stu.sex = "男";
stu.age = 2000;

程序設計的缺陷

外界可以隨意的對對象的屬性進行修改,賦值操作,沒有任何約束

封裝

實質是, 將類的狀態隱藏在類內部, 不允許外部程序直接訪問, 而是通過該類提供的方法來實現對隱藏信息的操作和訪問

優勢

  • 反映了事物的相對獨立性, 有效地避免了外部錯誤對對象的影響
  • 隱藏類的實現細節,讓使用者只能通過規定方式訪問數據, 限制不合理操作

使用方式

private int age;
/**
 * 給age 創建相對應的方法
 * 通過方法內部的邏輯 來限制外界的訪問
 */
public void setAge(int age){
    // 如果年齡在 0-127歲之間可以賦值
    if(age > 0 && age < 127){
        this.age = age;
    }else{
        System.out.println("年齡設置有誤!");
     }
}
public int getAge(){
    return age;
}

舉個栗子

想見明星

先和經紀人 預約, 經紀人條件列出來給你,出場費一百萬

包結構

包的作用

  • 包可以將類組成較小的單元 (類似於文件夾)
  • 防止命名衝突 (學生 中學生middle 大學生college)
  • 允許制定規則在更廣的範圍內保護類,數據和方法

語法標準

// 聲明 必須位於 java源文件的第一條非註釋語句
package 包結構;

包結構通用規範

  • 一個唯一的包,前綴通常是小寫的ASCII 字母, 並且是一個頂級域名,(com,cn,edu,gov,net,org)通常使用組織的網絡域名的逆序 (cn.bdqn)
  • 域名.公司名.項目名.項目模塊名

使用包結構

import college.Student;

回憶使用Scanner 類

import java.util.Scanner;

訪問權限修飾符

包結構是一種訪問控制機制,可以通過包限制和制約類之間的訪問關係

類的訪問修飾符

修飾符 同一個包 不同包
public 可以使用 可以使用
默認的 可以使用 不可以使用

類成員的修飾符

修飾符 同一個類中 同一包中 子類 不同包
public (公共的)
protected (受保護的) ×
默認 × ×
private(私有的) × × ×

static 修飾符

概念

static 含義 靜態的 表示一個類中的屬性或者方法是被該類的所有對象所共享

舉個栗子

學生是一個類

個性: 學生的姓名, 年齡都是屬於一個學生的特性

共性: 大家同處於一個教室 , 教室是屬於大家的, 不是屬於某一個學生的

該屬性 是公共的 不單獨屬於某一個對象,而是屬於所有對象
因爲對象 都是從類中實例化出來的(類是一個模板,對象是基於該模板的一個實例)
靜態屬於所有對象, 靜態是屬於類的 屬於模板的
教室中有飲水機 , 所有學生都可以使用, 但是沒有所有權,只有使用權

靜態屬性的調用

public class Student {
    static String classRoom = "公用機房";
    String name;
}

Student stu1 = new Student();
stu1.name = "張三";
System.out.println(stu1.classRoom);

Student stu2 = new Student();
stu2.name = "李四";
System.out.println(stu2.classRoom);

使用對象調用靜態 是不推薦的, 最好方式是使用類名調用

Student.classRoom

學習靜態static之前

成員屬性
成員方法

構造方法

成員代碼塊

在這裏插入圖片描述

學習靜態static之後

成員屬性

成員方法

成員代碼塊

靜態屬性

靜態方法

靜態代碼塊

構造方法

在這裏插入圖片描述

靜態和非靜態的執行順序

靜態 > 非靜態
非靜態 依賴於對象而存在的, 沒有對象就沒有非靜態的屬性
	學生的姓名 是非靜態, 如果沒有學生對象就沒有姓名
靜態 依賴於類存在,不依賴對象, 跟隨類的加載而加載
	教室 即使沒有開學, 沒有一個學生, 教室依然存在
// 在沒有創建任何對象的時候, 就可以使用 classRoom 屬性
System.out.println(Student.classRoom);
// 如果想要使用非靜態name屬性 必須創建對象
Student stu = new Student();
stu.name = "張三";
System.out.println(stu.name);

類變量和實例變量的對比

類變量(靜態變量)
    被static修飾的變量
    在內存中只有一個拷貝
    類內部,可在任何方法內直接訪問靜態變量
    其他類中,可以直接通過類名訪問
實例變量
    沒有被static修飾的變量
    每創建一個實例,就會爲實例變量分配一次內存,實例變量可以在內存中有多個拷貝,互不影響

在這裏插入圖片描述

程序運行流程

  1. 靜態屬性
  2. 靜態代碼塊
  3. 成員屬性
  4. 構造代碼塊
  5. 構造方法

靜態代碼只會加載一次 , 靜態內容在內存中只有一份

非靜態, 每一次創建對象都會被運行一次

靜態和非靜態之間的相互調用

非靜態可以使用 靜態方法和靜態屬性

靜態方法不可以使用非靜態屬性和非靜態方法 包括this關鍵字

public class Student {
    static String classRoom = "公用機房";
    // 依賴於某個具體對象的 沒有一個存在的學生, 就沒有學生姓名
    String name;

    public void study(){
        // 不會產生衝突問題
        System.out.println(name +"在"+classRoom+"學習");
    }
    // 靜態方法 可以直接使用類名來調用 , 不依賴於某一個具體對象
    public static void abc(){
        // name 依賴於某個具體對象的 沒有一個存在的學生, 就沒有學生姓名
        // 衝突問題
        System.out.println(name +"在"+classRoom+"學習");
    }
}

案例

模擬實現選民投票過程:一羣選民進行投票,每個選民只允許投一次票,並且當投票總數達到100時,就停止投票
投票次數 屬於選民的, 屬於所有選民,而不是某一個選民

繼承

書寫兩個類

貓狗案例 , 有很多相同的屬性 方法

抽取類之間的共性, 成爲父類(動物)

繼承的語法

子類 extends 父類 (is a 是一個 的關係)

public class Animal {
    String type;
    String name;
    String sex;
    int age;

    public void sleep(){}
    public void eat(){}
}
public class Dog extends Animal{
    public void lookDoor(){}
}
public class Cat extends Animal{
    public void catchMouse(){}
}

特性

繼承是Java中實現代碼重用的重要手段之一。

Java中只支持單根繼承,即一個類只能有一個直接父類

子類繼承父類, 繼承了父類所有非私有的屬性和方法

子類調用父類的內容

語法

// 調用父類屬性
super.name
// 調用父類的方法
super.eat();
// 調用父類的構造
super();
super(name);

注意點

super 只能出現在子類的方法和構造方法中

super 調用構造方法時,只能是第一句

super 不能訪問父類的private成員

繼承條件下的構造方法

1- 創建子類對象 默認去調用 父類的無參構造
2- 子類繼承父類, 擁有了父類的所有的非私有屬性, 子類就可以對這些屬性進行操作
3- 構造方法就是給屬性進行初始化的 , 子類構造方法沒有通過super顯式調用父類的有參構造方法,也沒通過this顯式調用自身其他構造方法 , 系統默認調用父類的無參構造方法

4- 子類構造方法通過super顯式調用父類的有參構造方法, 執行父類相應構造方法,而不執行父類無參構造方法

子父類之間代碼執行流程

在有繼承關係的兩個類, 代碼中的內容是如何執行的

class Father{
    屬性
    構造代碼塊
    構造方法
}
class Son extends Father{
    屬性
    構造代碼塊
    構造方法
}

流程

父類的 屬性 > 構造代碼塊 > 構造方法

子類的 屬性 > 構造代碼塊 > 構造方法

在有靜態內容加入的情況下

class Father{
	靜態屬性
    靜態構造代碼塊
    屬性
    構造代碼塊
    構造方法
}
class Son extends Father{
    靜態屬性
    靜態構造代碼塊
    構造方法
}

1- 父類的靜態屬性, 靜態代碼塊

2- 子類的靜態屬性, 靜態代碼塊

3- 父類的成員屬性,成員代碼塊, 構造方法

4- 子類的成員屬性,成員代碼塊, 構造方法

子類不能獲取父類的哪些資源

  • private成員
  • 子類與父類不在同包 , 使用默認訪問權限的成員
  • 構造方法

方法重寫

概念 :

子類根據需求對從父類繼承的方法進行重新編寫

重寫時,可以用super.方法的方式來保留父類的方法

構造方法不能被重寫 (子類不能繼承父類的構造方法)

方法重寫的規則

方法重寫(override): 發生在兩個有繼承關係的類中, 子類重寫繼承自父類的方法, 要求方法名,參數列表,返回值一致, 訪問修飾符權限不能低於父類,拋出異常不能高於父類

方法重載(overload): 發生在同一個類中, 方法名相同,參數列表不同,與訪問修飾符,返回值類型無關

  1. 方法名相同
  2. 參數列表相同
  3. 返回值相同或是其子類
  4. 訪問修飾符權限不能低於父類
  5. 拋出異常不能高於父類

在這裏插入圖片描述

Object 類

默認是所有類的父類

一個類如果不寫 extends 默認繼承Object類

Object(超類) 中國人 是炎黃子孫, 龍的傳人

在這裏插入圖片描述

toString()

A a = new A("李四",20);
//  System.out.println(a.toString());  // date0710.A@1b6d3586
// 對象是在堆內存中保存的, 都擁有一個地址信息 1b6d3586 十六進制的地址表示方式
// 如果用戶不希望看到類似於 date0710.A@1b6d3586 打印效果, 可以重寫該方法
System.out.println(a); // 默認去調用 該對象的 toString()方法

equals()

== 比較運算符

如果比較的是兩個基本數據類型 含義是直接比較值的大小

如果比較的是兩個引用數據類型 含義是比較兩個對象是否是同一對象

Object中 equals()方法 源碼

public boolean equals(Object obj) {
    return (this == obj);
}

案例

public class Student {
    int sId;
    String name;

    public Student(){}
    public Student(int sId,String name){
        this.sId = sId;
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        // 強轉類型
        Student stu = (Student)obj;

        return this.sId == stu.sId;
    }
}

public static void main(String[] args) {
    Student s1 = new Student(10086,"張三");
    Student s2 = new Student(10086,"張三");
    // 兩名學生 學號一致 就是同一個人
    System.out.println(s1.equals(s2));   // 使用父類的 equals  s1 == s2
}

含義

Object 中的方法, 用於比較兩個對象的地址是否相同, 一般要求子類重寫, 用於比較兩個對象的內容是否一致

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章