寫到這里終於寫到了入門篇的最后一個知識點了。類和對象是Java中經常被提到的兩個詞匯,實際上可以將類看作對象的載體,它定義了對象所具有的功能。Java是面向對象的語言,因此掌握類與對象是學習Java語言的基礎。
類和對象的概念就不在此描述了,這篇隨筆還是主要從代碼方面入手,在學習本篇前建議先了解一下類和對象的概念、實例的概念以及面向對象程序的特點,也即封裝、繼承、多態。
一、類
類是封裝對象的屬性和行為的載體,在Java語言中對象的屬性以成員變量的形式存在,而對象的方法以成員方法的形式存在。
1. 類的構造方法
構造方法是一個與類同名的方法,對象的創建就是通過構造方法完成的,構造方法分為有參構造方法和無參構造方法,區別就在於有沒有參數。說這么多概念是不是感覺有點麻木,直接看下面的例子吧。
1 public class Example { 2 3 public Example() { // 定義無參構造方法 4 System.out.println("無參構造方法"); 5 } 6 7 public Example(String name) { // 定義有參構造方法 8 System.out.println("有參構造方法"); 9 } 10 11 }
在定義構造方法時,構造方法沒有返回值,且構造方法不需要void關鍵字進行修飾。“public”是構造方法的修飾符,“Example”是構造方法的名稱。
在構造方法中可以為成員變量賦值,這樣當實例化一個本類的對象時,相應的成員變量也將被初始化。
2. 類的主方法
主方法其實我們已經見過很多次了,Java編譯器通過主方法來執行程序,是類的入口點,語法格式如下:
public static void main(String[] args) { // ... }
“static”是指主方法是靜態的,若在其中調用其它方法,則該方法也必須是靜態的;”void”是指主方法沒有返回值;“String[] args”是指主方法的形參為數組,用args[0]~args[n]分別表示程序的第一到第n個參數,可以使用args.length獲取參數的個數。
3. 成員變量
對象的屬性稱為成員變量,也可稱為屬性。下面以學生類(可比作學生證)舉個例子:
1 public class Student { 2 private int id; // 定義一個int型成員變量,學號 3 private String name; // 定義一個String型成員變量, 姓名 4 5 public Student() { // 定義無參構造方法 6 7 } 8 public Student(int id, String name) { // 定義有參構造方法 9 this.id = id; 10 this.name = name; 11 } 12 13 public void setName(String name) { // 定義一個setName()方法,用於導入學生姓名 14 this.name = name; // 將參數值賦給成員變量 15 } 16 public String getName() { // 定義一個getName()方法,用於獲取學生姓名 17 return this.name; 18 } 19 20 public Student getStudent() { // 返回Student類引用 21 return this; 22 } 23 }
這就是個比較全的例子了,在Java語言中使用class關鍵字來定義類,Student是類的名稱;在Student類中定義了三個成員變量,分別為學號和姓名,可設置初始值也可不設置初始值,若不設置初始值則會有默認值;private關鍵字用於定義一個私有成員,后面會介紹public、protected和private。接下來的兩個構造方法上面已經提到過了,this關鍵字用於引用對象的成員變量和方法,在后面會有所介紹。一般在這樣的類中每一個變量都會有set和get方法,set方法是帶參數的方法沒有返回值,get方法是有返回值的方法,用於獲取。最后還有一個getStudent()方法,它的類型是Student類的,用於返回Student類的引用,用this關鍵字實現。
4. 成員方法
成員方法對應類的行為,就是上述實例中的getName()和setName()方法,分別為獲取學生姓名和設置學生姓名的方法,語法格式如下:
權限修飾符 返回值類型 方法名(參數類型 參數名){ // ... return 返回值; }
若無返回值,返回值類型用void關鍵字表示,如上述setName()方法。若有返回值,返回值類型要與方法返回值類型一致。
5. 局部變量
如果在成員方法中定義一個變量,那么這個變量別稱為局部變量。例如在上述Student類中的getName()方法中定義一個局部變量id如下:
public String getName() { int id = 0; // 定義一個局部變量 return id + this.name; }
局部變量是在方法執行時創建,在方法執行結束時被銷毀,使用時必須賦值或初始化。所以局部變量的有效范圍從該變量的聲明開始到該變量的結束為止。
若一個方法中含有與成員變量同名的局部變量,則方法中對這個變量的訪問以局部變量進行訪問。例如id,在上述方法中id=0,而不是Student類中的成員變量id的值。
6. 靜態變量、常量和方法
由static修飾的變量、常量和方法被稱作靜態變量、常量和方法。靜態成員是屬於類所有的,區別於個別對象,可以在本類或其他類中使用類名和“.”運算符調用,這個在之前的篇幅中的例子也出現過,語法格式為: 類名.靜態類成員 。
1 public class StaticTest { 2 final static double PI = 3.1415926; // 在類中定義靜態常量 3 static int id; // 在類中定義靜態變量 4 5 public static void demo01() { 6 System.out.println("test"); 7 } 8 public static void main(String[] args) { 9 System.out.println(StaticTest.PI); // 調用靜態常量 10 System.out.println(StaticTest.id); // 調用靜態變量 11 StaticTest.demo01(); // 調用靜態方法 12 } 13 14 }
7. 權限修飾符
Java中的權限修飾符主要包括private、public和protected,這些修飾符控制着對類和類的成員變量以及成員方法的訪問。區別見下表:
訪問位置 | 類修飾符 | ||
private | protected | public | |
本類 | 可見 | 可見 | 可見 |
同包其他類或子類 | 不可見 | 可見 | 可見 |
其他包的類或子類 | 不可見 | 不可見 | 可見 |
若一個類的訪問權限為不可見,這個類將隱藏其內的所有數據,以免用戶直接訪問它。當聲明類時不使用public、protected或private修飾符設置類的權限,則這個類預設為包存取范圍,即只有同一個包中的類可以調用這個類的成員變量或成員方法。
要特別注意以下情況,在項目中com.adamjwh包下創建AnyClass類,該類使用默認權限時:
package com.adamjwh; class AnyClass { public void doString() { // ... } }
此時,即使AnyClass類中的doString()方法又被設置成public訪問權限,其訪問權限也與AnyClass類的訪問權限相同。因為Java規定,類的權限設定會約束類的成員上的權限設定,所以上述代碼等同於下面的代碼:
package com.adamjwh; class AnyClass { void doString() { // ... } }
8. this關鍵字
在Java中,this關鍵字被隱式地用於引用對象的成員變量和方法,如前面“成員變量”中的例子:
public void setName(String name) { // 定義一個setName()方法,用於導入學生姓名 this.name = name; // 將參數值賦給成員變量 }
setName()方法中,this.name指定的就是Student類中name變量,而“this.name=name”語句中第二個name則指定的是形參name。實質上,setName()方法實現的功能就是將形參name的值賦予成員變量name。
this除了可以調用成員變量或成員方法之外,還可以作為方法的返回值。如前面“成員變量”中的例子:
public Student getStudent() { // 返回Student類引用 return this; }
在getStudent()方法中,方法的返回值為Student類,所以方法體中使用return this這種形式將Student類的對象進行返回。
二、對象
Java是面向對象的程序設計語言,對象是由類抽象出來的,所有的問題都是通過對象來處理,對象可以操作類的基本屬性和方法解決相應的問題。
1. 對象的創建
在Java中可以使用new操作符調用構造方法創建對象,語法格式如下:
Test test = new Test(); Test test = new Test("a");
test對象被創建出來時,test對象就是一個對象的引用,這個引用在內存中為對象分配了存儲空間,可以在構造方法中初始化成員變量,當創建對象時,自動調用構造方法。
在Java中對象和實例事實上可以通用,下面看一個創建對象的實例。
public class CreateObject { public CreateObject() { // 構造方法 System.out.println("test"); } public static void main(String[] args) { new CreateObject(); // 創建對象
在上述實例的主方法中使用new操作符創建對象,在創建對象的同時,自動調用構造方法中的代碼。
2. 訪問對象的屬性和行為
當用戶使用new操作符創建一個對象后,可以使用“對象.類成員”來獲取對象的屬性和行為。話不多說,直接上代碼。
1 public class ObjectTest { 2 3 int i = 2018; // 成員變量 4 public void call() { // 成員方法 5 for(i=0; i<3; i++) { 6 System.out.print(i + " "); 7 if(i == 2 ) { 8 System.out.println(); // 換行 9 } 10 } 11 } 12 13 public ObjectTest() { // 構造方法 14 } 15 16 public static void main(String[] args) { 17 ObjectTest o1 = new ObjectTest(); // 創建一個對象 18 ObjectTest o2 = new ObjectTest(); // 創建另一個對象 19 o2.i = 60; // 給第二個類成員變量賦值 20 21 System.out.println("第一個實例對象調用變量i的結果為:"+ o1.i); 22 o1.call(); 23 System.out.println("第二個實例對象調用變量i的結果為:"+ o2.i); 24 o2.call(); 25 } 26 27 }
運行結果如下:
這里我們可以看到,雖然使用兩個對象調用同一個成員變量,結果卻不相同,因為在打印這個成員變量的值之前將該值重新賦值為60,但在賦值時使用的是第二個對象o2調用的成員變量,所以在第一個對象o1調用成員變量打印該值時仍然是成員變量的初始值。所以兩個對象的產生是相互獨立的。
如果希望成員變量不被其中任何一個對象改變,可以使用static關鍵字,也即改第三行代碼為 static int i = 2018; ,運行結果如下:
這里由於第19行代碼“o2.i=60;”改變了靜態成員變量的值,所以使對象o1調用成員變量的值也變為了60;當“o1.i”執行完后,再次調用call()方法,使i的值又重新賦值為0,循環打印,最后i為3,退出循環,所以對象o2調用成員變量的值變成了3。
3. 對象的引用、比較和銷毀
對象引用的語法格式為: 類名 引用對象名稱 ,例如一個Student類的引用可以為: Student student; ,引用與對象相關聯的語法為: Student student = new Student(); .
對象的比較有“==”運算符和equals()方法兩種,區別在上一篇中已經介紹過了。equals()方法是String類中的方法,用於比較兩個對象引用所指的內容是否相等;而“==”運算符比較的是兩個對象引用的地址是否相等。
對象的銷毀利用的是Java中的垃圾回收機制,用戶不必擔心廢棄的對象占用內存,垃圾回收器將回收無用的占用內存的資源。會被Java虛擬機視為垃圾的對象主要包括以下兩種情況:
(1) 對象引用超過其作用范圍;
(2) 將對象賦值為null;
雖然垃圾回收機制已經很完善,但垃圾回收器只能回收那些由new操作符創建的對象。所以Java中提供了一個finalize()方法,如果用戶在類中定義了finalize()方法,在垃圾回收時首先調用該方法,並且在下一次垃圾回收動作發生時,才能真正的回收對象占有的內存。由於垃圾回收不受人為控制,Java還提供了System.gc()方法強制啟動垃圾回收器,作用是告知垃圾回收器來清理。
到此就是Java入門篇的全部內容了,要熟練使用Java語言還有許多知識等着我們去挖掘,掌握入門篇的知識應付學校的考試之類的是沒有問題的,如果還想做一些游戲或項目,還需要進一步學習Java語言的知識,下一篇開始就是Java的進階篇了,主要內容包括接口、繼承、多態、異常處理、輸入輸出、Java集合類以及Swing程序設計(圖形界面)等等。