P06_類與物件-封裝-構造方法
第1章 面向物件思想
1.1 面向物件思想概述
概述
Java語言是一種面向物件的程式設計語言,而面向物件思想是一種程式設計思想,我們在面向物件思想的指引下,使用Java語言去設計、開發計算機程式。 這裡的物件泛指現實中一切事物,每種事物都具備自己的屬性和行為。面向物件思想就是在計算機程式設計過程中,參照現實中事物,將事物的屬性特徵、行為特徵抽象出來,描述成計算機事件的設計思想。 它區別於面向過程思想,強調的是通過呼叫物件的行為來實現功能,而不是自己一步一步的去操作實現。
特點
面向物件思想是一種更符合我們思考習慣的思想,它可以將複雜的事情簡單化,並將我們從執行者變成了指揮者。面向物件的語言中,包含了三大基本特徵,即封裝、繼承和多型。
1.2 類和物件
什麼是類
- 類:是一組相關屬性和行為的集合。可以看成是一類事物的模板,使用事物的屬性特徵和行為特徵來描述該類事物。
現實中,描述一類事物:
- 屬性:就是該事物的狀態資訊。
- 行為:就是該事物能夠做什麼。
什麼是物件
- 物件:是一類事物的具體體現。物件是類的一個例項(物件並不是找個女朋友),必然具備該類事物的屬性和行為.
類與物件的關係
- 類是對一類事物的描述,是抽象的。
- 物件是一類事物的例項,是具體的。
- 類是物件的模板,物件是類的實體。
1.3 類的定義
事物與類的對比
現實世界的一類事物:
-
屬性:事物的狀態資訊。
-
行為:事物能夠做什麼。
Java中用class描述事物也是如此:
- 成員變數:對應事物的屬性
- 成員方法:對應事物的行為
類的定義格式
public class ClassName {
//成員變數
//成員方法
}
- 定義類:就是定義類的成員,包括成員變數和成員方法。
- 成員變數:和以前定義變數幾乎是一樣的。只不過位置發生了改變。在類中,方法外。
- 成員方法:和以前定義方法幾乎是一樣的。只不過把static去掉,static的作用在面向物件後面課程中再詳細講解。
類的定義格式舉例:
public class Student { //成員變數 String name;//姓名 int age;//年齡 //成員方法 //學習的方法 publicvoid study() { System.out.println("好好學習,天天向上"); } //吃飯的方法 publicvoid eat() { System.out.println("學習餓了要吃飯"); } }
1.4 物件的使用
物件的使用格式
建立物件:
類名 物件名 = new 類名();
使用物件訪問類中的成員:
物件名.成員變數;
物件名.成員方法();
1.5 類與物件的練習
定義手機類:
public class Phone {
// 成員變數
String brand; //品牌
int price; //價格
String color; //顏色
// 成員方法
//打電話
public void call(String name) {
System.out.println("給"+name+"打電話");
}
//發簡訊
public void sendMessage() {
System.out.println("群發簡訊");
}
}
定義測試類:
public class Test02Phone {
public static void main(String[] args) {
//建立物件
Phone p = new Phone();
//輸出成員變數值
System.out.println("品牌:"+p.brand);//null
System.out.println("價格:"+p.price);//0
System.out.println("顏色:"+p.color);//null
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐");
//給成員變數賦值
p.brand = "錘子";
p.price = 2999;
p.color = "棕色";
//再次輸出成員變數值
System.out.println("品牌:"+p.brand);//錘子
System.out.println("價格:"+p.price);//2999
System.out.println("顏色:"+p.color);//棕色
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐");
//呼叫成員方法
p.call("紫霞");
p.sendMessage();
}
}
1.6 物件記憶體圖
一個物件,呼叫一個方法記憶體圖
- 通過上圖,我們可以理解,在棧記憶體中執行的方法,遵循"先進後出,後進先出"的原則。變數p指向堆記憶體中的空間,尋找方法資訊,去執行該方法。
- 但是,這裡依然有問題存在。建立多個物件時,如果每個物件內部都儲存一份方法資訊,這就非常浪費記憶體了,因為所有物件的方法資訊都是一樣的。那麼如何解決這個問題呢?請看如下圖解。
兩個物件,呼叫同一方法記憶體圖
- 物件呼叫方法時,根據物件中方法標記(地址值),去類中尋找方法資訊。這樣哪怕是多個物件,方法資訊只儲存一份,節約記憶體空間。
一個引用,作為引數傳遞到方法中記憶體圖
- 引用型別作為引數,傳遞的是地址值。
1.7 成員變數和區域性變數區別
變數根據定義位置的不同,我們給變數起了不同的名字。如下圖所示:
- 在類中的位置不同
成員變數:類中,方法外 區域性變數:方法中或者方法宣告上(形式引數) - 作用範圍不一樣
成員變數: 類中 區域性變數: 方法中 - 初始化值的不同
成員變數:有預設值 區域性變數:沒有預設值。必須先定義,賦值,最後使用 - 在記憶體中的位置不同
成員變數:堆記憶體 區域性變數:棧記憶體 - 生命週期不同
成員變數:隨著物件的建立而存在,隨著物件的消失而消失 區域性變數:隨著方法的呼叫而存在,隨著方法的呼叫完畢而消失
第2章 封裝
2.1 概述和原則
概述
面向物件程式語言是對客觀世界的模擬,客觀世界裡成員變數都是隱藏在物件內部的,外界無法直接操作和修改。封裝可以被認為是一個保護屏障,防止該類的程式碼和資料被其他類隨意訪問。要訪問該類的資料,必須通過指定的方式。適當的封裝可以讓程式碼更容易理解與維護,也加強了程式碼的安全性。
原則
將屬性隱藏起來,若需要訪問某個屬性,提供公共方法對其訪問。
2.2 封裝的操作步驟
- 使用 private 關鍵字來修飾成員變數。
- 對需要訪問的成員變數,提供對應的一對 getXxx 方法 setXxx 方法。
2.3 封裝的操作——private關鍵字
private的含義
- private是一個許可權修飾符,代表最小許可權。
- 可以修飾成員變數和成員方法。
- 被private修飾後的成員變數和成員方法,只在本類中才能問。
private 使用格式
private 資料型別 變數名 ;
使用 private 修飾成員變數,程式碼如下:
public class Student {
private String name;
private int age;
}
提供 getXxx 方法 / setXxx 方法,可以訪問成員變數,程式碼如下:
public class Student {
private String name;
private int age;
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
}
2.4 封裝的優化1——this關鍵字
我們發現 setXxx 方法中的形參名字並不符合見名知意的規定,那麼如果修改與成員變數名一致,是否就見名知意了呢?程式碼如下:
public class Student {
private String name;
private int age;
public void setName(String name) {
name = name;
}
public void setAge(int age) {
age = age;
}
}
經過修改和測試,我們發現新的問題,成員變數賦值失敗了。也就是說,在修改了setXxx() 的形參變數名後,方法並沒有給成員變數賦值!這是由於形參變數名與成員變數名重名,導致成員變數名被隱藏,方法中的變數名,無法訪問到成員變數,從而賦值失敗。所以,我們只能使用this關鍵字,來解決這個重名問題。
this的含義
this代表所在類的當前物件的引用(地址值),即物件自己的引用。
記住 :方法被哪個物件呼叫,方法中的this就代表那個物件。即誰在呼叫,this就代表誰。
this使用格式
this.成員變數名;
使用 this 修飾方法中的變數,解決成員變數被隱藏的問題,程式碼如下:
public class Student {
private String name;
private int age;
public void setName(String name) {
//name = name;
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
//age = age;
this.age = age;
}
public int getAge() {
return age;
}
}
- :方法中只有一個變數名時,預設也是使用 this 修飾,可以省略不寫。
2.5 封裝的優化2——構造方法
當一個物件被建立時候,構造方法用來初始化該物件,給物件的成員變數賦初始值。
- 無論你與否自定義構造方法,所有的類都有構造方法,因為Java自動提供了一個無引數構造方法,一旦自己定義了構造方法,Java自動提供的預設無引數構造方法就會失效。
構造方法的定義格式
修飾符 構造方法名(引數列表){
// 方法體
}
構造方法的寫法上,方法名與它所在的類名相同。它沒有返回值,所以不需要返回值型別,甚至不需要void。使用構造方法後,程式碼如下:
public class Student {
private String name;
private int age;
// 無引數構造方法
public Student() {}
// 有引數構造方法
public Student(String name,int age) {
this.name = name;
this.age = age;
}
}
注意事項
- 如果你不提供構造方法,系統會給出無引數構造方法。
- 如果你提供了構造方法,系統將不再提供無引數構造方法。
- 構造方法是可以過載的,既可以定義引數,也可以不定義引數。
2.6 標準程式碼——JavaBean
JavaBean 是 Java語言編寫類的一種標準規範。符合JavaBean 的類,要求類必須是具體的和公共的,並且具有無引數的構造方法,提供用來操作成員變數的set 和get 方法。
public class ClassName{
//成員變數
//構造方法
//無參構造方法【必須】
//有參構造方法【建議】
//成員方法
//getXxx()
//setXxx()
}
編寫符合JavaBean 規範的類,以學生類為例,標準程式碼如下:
public class Student {
//成員變數
private String name;
private int age;
//構造方法
public Student() {}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
//成員方法
publicvoid setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
publicvoid setAge(int age) {
this.age = age;
}
publicint getAge() {
return age;
}
}
測試類,程式碼如下:
public class TestStudent {
public static void main(String[] args) {
//無參構造使用
Student s= new Student();
s.setName("柳巖");
s.setAge(18);
System.out.println(s.getName()+"‐‐‐"+s.getAge());
//帶參構造使用
Student s2= new Student("趙麗穎",18);
System.out.println(s2.getName()+"‐‐‐"+s2.getAge());
}
}