文章目錄
面向對象有三大特性 : 封裝 繼承 多態
封裝
程序設計中遇到的問題
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修飾的變量
每創建一個實例,就會爲實例變量分配一次內存,實例變量可以在內存中有多個拷貝,互不影響
程序運行流程
- 靜態屬性
- 靜態代碼塊
- 成員屬性
- 構造代碼塊
- 構造方法
靜態代碼只會加載一次 , 靜態內容在內存中只有一份
非靜態, 每一次創建對象都會被運行一次
靜態和非靜態之間的相互調用
非靜態可以使用 靜態方法和靜態屬性
靜態方法不可以使用非靜態屬性和非靜態方法 包括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): 發生在同一個類中, 方法名相同,參數列表不同,與訪問修飾符,返回值類型無關
- 方法名相同
- 參數列表相同
- 返回值相同或是其子類
- 訪問修飾符權限不能低於父類
- 拋出異常不能高於父類
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 中的方法, 用於比較兩個對象的地址是否相同, 一般要求子類重寫, 用於比較兩個對象的內容是否一致