Java 類和對象
經(jīng)過前面一系列的學(xué)習(xí),你可能對類和對象已經(jīng)有了一定的了解,這是因為 Java 語言是純面向?qū)ο蟮木幊陶Z言,類和對象在 Java 中無處不在。
在程序設(shè)計時,我們針對事物的特征和行為使用代碼進(jìn)行實現(xiàn),就是面向?qū)ο缶幊?。可以毫不夸張地說,面向?qū)ο缶幊淌侵写笮晚椖看a最好的組織形式。
本小節(jié)我們將學(xué)習(xí)類和對象的基本概念、類和對象的關(guān)系,除了字段和方法,在類中都可以定義什么其他內(nèi)容。也會講解什么是實例化、實例化過程是怎樣的,構(gòu)造方法是什么,如何定義以及其特點,this
關(guān)鍵字的含義和使用。
1. 類和對象
1.1 什么是類
我們在前面的學(xué)習(xí)中已經(jīng)知道,類 (class) 是一個程序的基本單位,我們之前所編寫的 .java
文件都是類。在現(xiàn)實生活中,慕課網(wǎng)學(xué)生可以是一個類、交通工具可以是一個類、NBA 球員可以是一個類。例如,如下代碼聲明了一個慕課網(wǎng)學(xué)生類:
public class ImoocStudent {
...
}
1.2 什么是對象
你也許聽到過一句話:“萬物皆對象”。是的,現(xiàn)實世界中所有的事物,都可以是對象。例如一個慕課網(wǎng)學(xué)生、一輛汽車、NBA 巨星喬丹等等,都是對象。 對象是具體的一個事物。下面我們來看一下類和對象的關(guān)系。
1.3 類和對象的關(guān)系
類是一個抽象的概念,可以將它理解成 “模板”,可用于產(chǎn)生對象;而對象是一個具體的事物。
ImoocStudent
是一個類,毋庸置疑,它是抽象的,不能表示一個具體的事物;而屏幕面前的你作為慕課網(wǎng)學(xué)生,就是一個對象,因為你是實實在在的、具體的一個慕課網(wǎng)學(xué)生,和你一樣的在慕課網(wǎng)學(xué)習(xí)的其他同學(xué),都可以理解為是由 ImoocStudent
類產(chǎn)生的一個個具體的對象。
例如,很多 NBA 球星:科比、喬丹、詹姆斯等他們都是具體的球員,具體的球員就是對象,而這樣一組對象在代碼中可以抽象為類。
2. 定義類
定義類的語法,相信大家都已經(jīng)熟練掌握,下面我們就以慕課網(wǎng)學(xué)生為例,初步抽象出一個簡單的慕課網(wǎng)學(xué)生類。
Tips:在本小節(jié)的剩余內(nèi)容中,我們都將圍繞這個例子展開學(xué)習(xí)。下面請跟上節(jié)奏認(rèn)真思考。
2.1 慕課網(wǎng)學(xué)生類
在代碼中,事物的靜態(tài)特征被抽象成屬性,事物的動態(tài)行為被抽象成方法。一個基本的慕課網(wǎng)學(xué)生類可以包含若干屬性和方法。
慕課網(wǎng)學(xué)生可以有昵稱、職位、城市、性別等特征,如下是慕課網(wǎng)個人中心的截圖:

除了這些特征,還可以有學(xué)習(xí)課程、評論、發(fā)表手記等行為。有了這些特征和行為,我們就可以抽象出一個慕課網(wǎng)學(xué)生類:
public class ImoocStudent {
// 定義屬性(特征)
String nickname; // 昵稱
String position; // 職位
String city; // 城市
String sex; // 男 | 女
// 定義方法(行為)
public void studyCourse() {
System.out.println("學(xué)習(xí)課程");
}
public void postComment() {
System.out.println("發(fā)表評論");
}
public void postArticle() {
System.out.println("發(fā)表手記");
}
}
2.2 組成類的元素
Tips:類組成元素屬于擴(kuò)展內(nèi)容,此處有一個整體認(rèn)識即可。隨著面向?qū)ο蟮纳钊雽W(xué)習(xí),知識點都會涵蓋。
剛剛我們通過對現(xiàn)實生活中慕課網(wǎng)學(xué)生的分析,抽象出了慕課網(wǎng)學(xué)生類,并在類中定義了一些屬性和方法。那么除了屬性和方法,類中還可以有什么其他元素呢?
下面我們來詳細(xì)介紹,每個類都可以由以下元素組成:
- 成員屬性:也稱為字段,成員變量或?qū)嵗兞?,屬性是用以保?strong>每個對象的數(shù)據(jù)的變量,例如每個慕課網(wǎng)學(xué)生都可能有昵稱、性別等。每個對象之間的屬性相互獨立,互不干擾;
- 成員方法:也稱實例方法,成員方法是對對象執(zhí)行的操作,例如,一個慕課網(wǎng)學(xué)生有一種方法來進(jìn)行發(fā)表評論;
- 靜態(tài)變量:也稱為類屬性,它是同一個類的任何對象所共有的。例如,一個慕課網(wǎng)學(xué)生類中的最后一個被添加的學(xué)生 ID,可以用靜態(tài)變量標(biāo)記。 一個類不管被實例化了多少對象,每個靜態(tài)變量在類中僅存在一次;
- 靜態(tài)方法:也稱為類方法,靜態(tài)方法是不影響特定對象的方法;
- 內(nèi)部類:可以將一個類包含在另一個類中,常用于該類僅提供給聲明它的類使用的情況;
- 構(gòu)造方法:生成新對象的特殊方法;
- 參數(shù)化類型:可以在定義期間將參數(shù)化類型分配給類。 參數(shù)化類型將替換為在類實例化時指定的類型。 它由編譯器完成。 它類似于 C 語言宏
#define
語句,其中預(yù)處理器評估宏。
3. 對象的實例化
3.1 創(chuàng)建對象
上面我們已經(jīng)定義了慕課網(wǎng)學(xué)生類,有了類就可以產(chǎn)生對象了。這里的產(chǎn)生對象指的就是對象的實例化操作,在 Java 中,使用 new
關(guān)鍵字實例化對象,其語法為:
類名 對象名稱 = new 類名();
類是對象的類型,因此我們以類名作為對象類型,對象名稱的命名規(guī)范與變量相同。例如,實例化一個慕課網(wǎng)學(xué)生對象,對象名稱命名為 student
:
ImoocStudent student = new ImoocStudent();
關(guān)于對象的實例化過程,可以分為兩部分:
- 聲明對象:在內(nèi)存的??臻g中執(zhí)行。
ImoocStudent student;
- 實例化對象:在內(nèi)存的堆空間執(zhí)行。
new ImoocStudent();
3.2 調(diào)用屬性和方法
對象實例化后,可以調(diào)用其屬性和方法,其語法為:
// 調(diào)用屬性
對象名.屬性名;
// 調(diào)用方法
對象名.方法名();
下面我們在 ImoocStudent
類的主方法中實例化一個慕課網(wǎng)學(xué)生對象,并依次調(diào)用其屬性和方法:
public class ImoocStudent {
// 定義屬性(特征)
String nickname; // 昵稱
String position; // 職位
String city; // 城市
String sex; // 男 | 女
// 定義方法(行為)
public void studyCourse() {
System.out.println("學(xué)習(xí)課程");
}
public void postComment() {
System.out.println("發(fā)表評論");
}
public void postArticle() {
System.out.println("發(fā)表手記");
}
public static void main(String[] args) {
// 實例化學(xué)生對象
ImoocStudent student = new ImoocStudent();
// 調(diào)用并打印成員屬性
System.out.println("昵稱:" + student.nickname);
System.out.println("職位:" + student.position);
System.out.println("城市:" + student.city);
System.out.println("性別:" + student.sex);
// 調(diào)用成員方法
student.studyCourse();
student.postComment();
student.postArticle();
}
}
運行結(jié)果:
昵稱:null
職位:null
城市:null
性別:null
學(xué)習(xí)課程
發(fā)表評論
發(fā)表手記
根據(jù)運行結(jié)果,我們看到了成員屬性和成員方法都被成功調(diào)用。但所有的屬性值都為 null
,這是因為成員屬性沒有默認(rèn)值,系統(tǒng)會給一個默認(rèn)初值。
Tips:不同數(shù)據(jù)類型的屬性會有不同的初值。此例中的屬性,都為字符串,默認(rèn)初值為
null
,你也可以嘗試為ImoocStudent
類添加其他類型的屬性,來看看它們各自的默認(rèn)初值。這里不再一一演示。
3.3 給屬性賦值
給成員屬性賦值的語法為:
對象名.屬性名 = 屬性值;
下面我們來修改一下在主方法中的代碼:
public class ImoocStudent {
// 定義屬性(特征)
String nickname; // 昵稱
String position; // 職位
String city; // 城市
String sex; // 男 | 女
// 定義方法(行為)
public void studyCourse() {
System.out.println("學(xué)習(xí)課程");
}
public void postComment() {
System.out.println("發(fā)表評論");
}
public void postArticle() {
System.out.println("發(fā)表手記");
}
public static void main(String[] args) {
// 實例化學(xué)生對象
ImoocStudent student = new ImoocStudent();
// 給成員屬性賦值
student.nickname = "Colorful";
student.position = "服務(wù)端工程師";
student.city = "北京";
student.sex = "男";
// 調(diào)用成員屬性
System.out.println("昵稱:" + student.nickname);
System.out.println("職位:" + student.position);
System.out.println("城市:" + student.city);
System.out.println("性別:" + student.sex);
}
}
運行結(jié)果:
昵稱:Colorful
職位:服務(wù)端工程師
城市:北京
性別:男
4. 構(gòu)造方法
4.1 概述
在類中,可定義一個構(gòu)造方法,也稱為構(gòu)造函數(shù)或構(gòu)造器。它用于一些初始化操作,構(gòu)造方法的語法為:
public 構(gòu)造方法名(參數(shù)) {
// 代碼塊
}
需要注意的是,與普通的自定義方法不同,構(gòu)造方法沒有返回類型,并且方法名要與類名同名。
另外,如果我們沒有定義構(gòu)造方法,系統(tǒng)會有一個默認(rèn)的構(gòu)造方法。換句話說:任何一個類都會有一個構(gòu)造方法。
構(gòu)造方法只能在對象的實例化時使用,也就是說,構(gòu)造方法只能配合 new
關(guān)鍵字使用。
根據(jù)參數(shù)的有無,構(gòu)造方法可分為兩種:
- 無參構(gòu)造方法
- 有參構(gòu)造方法
4.2 無參構(gòu)造方法
在 ImoocStudent
類中,我們可以定義一個無參構(gòu)造方法:
// 定義構(gòu)造方法,無返回值并且命名與類名相同
public ImoocStudent() {
// 執(zhí)行輸出語句
System.out.println("無參構(gòu)造方法執(zhí)行了...");
}
使用 new
關(guān)鍵字調(diào)用構(gòu)造方法:
ImoocStudent student = new ImoocStudent();
運行結(jié)果:
無參構(gòu)造方法執(zhí)行了...
4.3 有參構(gòu)造方法
當(dāng)創(chuàng)建實例對象時,我們經(jīng)常需要同時初始化這個實例的成員屬性,例如:
ImoocStudent student = new ImoocStudent();
student.nickname = "慕女神";
student.position = "UI設(shè)計師";
雖然這樣能夠給我們的成員屬性進(jìn)行賦值,但每次需要編寫 2 行這樣的代碼。能不能在創(chuàng)建對象時,就對這些屬性進(jìn)行賦值呢?有參構(gòu)造方法解決了這樣的問題,我們可以在 ImoocStudent
類內(nèi)部定義一個有參構(gòu)造方法:
// 有參構(gòu)造方法
public ImoocStudent(String studentNickname, String studentPosition) {
// 將參數(shù)變量賦值給實例變量
nickname = studentNickname;
position = studentPosition;
}
構(gòu)造函數(shù)中,我們將參數(shù)變量的值賦值給實例變量。使用 new
關(guān)鍵字調(diào)用構(gòu)造方法:
ImoocStudent student1 = new ImoocStudent("慕女神", "UI設(shè)計師");
System.out.println("昵稱為:" + student1.nickname);
System.out.println("職位為:" + student1.position);
運行結(jié)果:
昵稱為:慕女神
職位為:UI設(shè)計師
你也可以增加構(gòu)造函數(shù)的參數(shù)數(shù)量,以用來給更多的實例屬性賦值:
// 有參構(gòu)造方法
public ImoocStudent(String studentNickname, String studentPosition, String studentCity, String studentSex) {
nickname = studentNickname;
position = studentPosition;
city = studentCity;
sex = studentSex;
}
構(gòu)造方法與普通方法相同,也會重載,因此類中允許定義多個參數(shù)列表不同構(gòu)造方法。
需要特別注意的是,我們在上面兩個有參構(gòu)造方法中,成員屬性的命名和參數(shù)變量的命名是不同的,如果參數(shù)列表中參數(shù)變量的命名和實例屬性相同。將無法完成對實例屬性的賦值,也就是說,下面的寫法是錯誤的:
public ImmocStudent(String nickname) {
nickname = nickname;
}
這是因為構(gòu)造方法在參數(shù)的賦值過程中,會優(yōu)先到同一個作用范圍內(nèi)的 nickname
進(jìn)行賦值操作,這就是所謂的就近原則。這時我們可以使用 this
關(guān)鍵字。
5. this 關(guān)鍵字
為了解決上面無法使用與成員屬性同名稱的參數(shù)對成員屬性進(jìn)行賦值的問題,我們可以使用 this
關(guān)鍵字:
public ImmocStudent(String nickname) {
this.nickname = nickname;
}
在方法內(nèi)部,this
關(guān)鍵字是當(dāng)前對象的默認(rèn)引用,簡單說,誰調(diào)用了它誰就是 this
。因此,通過 this.field
就可以訪問當(dāng)前實例的字段,解決實例變量和參數(shù)變量名稱沖突的問題。
如下是本小節(jié)的最終實例代碼:
public class ImoocStudent {
// 定義屬性(特征)
String nickname; // 昵稱
String position; // 職位
String city; // 城市
String sex; // 男 | 女
// 無參構(gòu)造方法
public ImoocStudent() {
// 執(zhí)行輸出語句
System.out.println("無參構(gòu)造方法執(zhí)行了...");
}
// 有參構(gòu)造方法
public ImoocStudent(String nickname, String position) {
// 將參數(shù)變量賦值給實例變量
this.nickname = nickname;
this.position = position;
}
// 有參構(gòu)造方法
public ImoocStudent(String nickname, String position, String city, String sex) {
this.nickname = nickname;
this.position = position;
this.city = city;
this.sex = sex;
}
// 定義方法(行為)
public void studyCourse() {
System.out.println("學(xué)習(xí)課程");
}
public void postComment() {
System.out.println("發(fā)表評論");
}
public void postArticle() {
System.out.println("發(fā)表手記");
}
public static void main(String[] args) {
// 實例化學(xué)生對象
ImoocStudent student = new ImoocStudent();
// 給成員屬性賦值
student.nickname = "Colorful";
student.position = "服務(wù)端工程師";
student.city = "北京";
student.sex = "男";
// 調(diào)用成員屬性
System.out.println("昵稱:" + student.nickname);
System.out.println("職位:" + student.position);
System.out.println("城市:" + student.city);
System.out.println("性別:" + student.sex);
ImoocStudent student1 = new ImoocStudent("慕女神", "UI設(shè)計師");
System.out.println("昵稱為:" + student1.nickname);
System.out.println("職位為:" + student1.position);
}
}
無參構(gòu)造方法執(zhí)行了...
昵稱:Colorful
職位:服務(wù)端工程師
城市:北京
性別:男
昵稱為:慕女神
職位為:UI設(shè)計師
6. 小結(jié)
本小節(jié)中,我們初步熟悉了 Java 中的類和對象。我們再來回顧一下本小節(jié)的重點知識:
在面向?qū)ο笾?,類和對象?“模板” 和 “實例” 的關(guān)系。
類中的實例變量是每個實例獨自擁有的,它們互不干擾。
關(guān)于對象的實例化,我們是使用 new
關(guān)鍵字 + 構(gòu)造方法名 () 來實現(xiàn)的。
當(dāng)類內(nèi)部我們沒有顯示定義構(gòu)造方法時,系統(tǒng)會自動添加無參的構(gòu)造方法;當(dāng)在類內(nèi)部顯示定義了構(gòu)造方法,系統(tǒng)不會自動添加無參構(gòu)造方法。
this
關(guān)鍵字可以解決實例變量和參數(shù)變量沖突的問題;this
關(guān)鍵字也可以調(diào)用同一類中其他的成員方法。