一、面向對象編程
面向對象編程三大特性:封裝、繼承和多態。
類是實現封裝的手段,是面向對象編程的基本單元。
封裝隱藏了類的內部實現細節,暴露給外界可控的操作,提高數據的完整性和安全性,提高模塊的可重用性和開發效率,降低開發的復雜性。
從面向對象程序設計方法的角度看,程序中所有的東西都是對象,而程序是對象的組合,對象間通過消息傳遞實現協作。
二、類
類是Java程序設計的核心概念和基本單元。
類是對一類事物的特征的描述,是抽象后的描述;對象是一個實例。
1、Java沒有全局變量,只有:
靜態變量:隸屬於類
實例變量:類體中定義,類的屬性,隸屬於對象。
局部變量:形參、方法內定義或代碼塊中定義,隸屬於方法。
2、成員修飾符——public、private、protected、default
作用:實現訪問權限控制。
public:被public修飾的成員,可以在任何一個類中被調用。
private:除了本類的方法能夠調用私有成員(方法、屬性),其他任何類都不能直接訪問私有成員。
所有修飾符都能修飾數據成員、方法成員和構造方法;只有public和default能修飾類(外部類)。
3、方法重載
(1)方法名相同
(2)方法的參數簽名不相同(參數類型、個數、順序)。
(3)方法的返回類型可以不同,方法的修飾符也可以不同
三、對象
3.1 構造方法
與類名同名,不返回任何數據類型(實際上沒有返回任何東西),沒有void,不能有任何非訪問性質的修飾符。
類中可以有多個構造方法——應用了方法重載,每個構造方法在被調用后將在堆內存中創建一個對象然后向調用者返回一個該對象的引用(這里的引用,是指對象在堆內存空間中的首地址)
this,表示一個對象引用,其值指向正在執行方法的對象;
特別地,構造方法中,通過this調用其他構造方法時,必須放在第一行;
構造方法只能通過this調用一次其他構造方法;
關鍵字new的作用是(調用)一個構造函數,為對象分配內存空間,返回這塊內存的引用。
如果沒有顯示定義構造方法,類將會隱式定義一個默認情況下不接受任何參數的構造函數並將所有實例變量初始化為默認值。
原始數字類型的實例變量默認值為0,布爾類型變量為false,引用類型變量為null。
只要沒有將類中的變量進行初始化,它就會有默認值。但是final變量可以把初始化放到構造方法中進行,而static final必須在聲明時就進行初始化。
3.2 創建對象
創建對象的過程即類實例化的過程,包括類的加載、對象內存分配和變量初始化。
(1)new顯示創建
Cat ketty=new Cat();
new操作符,在內存中為對象開辟空間,它在堆內存上為對象開辟空間,動態地分配內存(主要存放對象的實例變量)。“動態分配“的意思是在程序運行時內存才會被分配,這樣你可以創建任意數量的對象。
ketty稱為對象引用,表示可以指向一個Cat類型的實例。ketty位於棧中。
等號賦值,將右邊在堆中創建的對象的內存空間的首地址賦予了對象的引用變量ketty。
(2)調用java.lang.Class類的newInstance()方法
Java中的任何類都包含有有一個Class類,它描述該類的元數據。通過調用Class類的類方法,創建對象:
Cat ketty=Cat.getClass().newInstance();
或者使用動態類加載語句(需存在相應的.class文件即可)創建:
Cat ketty=(Cat) Class.forName("Cat").newInstance();
通過類加載器方式創建類必須保證被創建的類在搜索路徑中存在相應的.class文件。
newInstance()方法創建對象實例會調用無參構造函數,所以必須確保類中存在無參數的構造函數,否則會有異常。
private修飾構造方法:
有時希望控制對象的生成或者阻止直接通過new在類的外部生成類的實例,這時用private修飾構造方法。單例設計模式就是通過此方法實現只創建一個對象的實例。
public class Singleton{ private static Singleton instance=null; private Singleton(){ System.out.println("private singleton is caled!") } public static Singleton getInstance(){ if(instance==null) instance=new Singleton(); return instance; } }
3.3 使用對象
適用對象必須通過對象的引用,像c中的指針,但不能像指針那樣直接修改引用值,而是只能通過它執行對象操作。
將一個對象的引用賦值給另一個引用時,實際上復制的是對象的引用地址,結果是兩個引用指向同一個對象。
3.4 Java的方法的參數傳遞機制——值傳遞
當傳遞一個參數時,方法獲得該參數的一個副本。
事實上,傳遞的參數會有倆種:基本類型的變量和對象的引用變量。
基本類型的變量,意味着變量值本身被復制,並傳遞給方法,因此,方法中對變量的修改不會影響原變量;
對象的引用變量,即對象的引用值(堆中的首地址)被復制,傳遞給方法。方法中的操作可以影響對象。
3.5 垃圾回收機制
一個對象不再被使用,應該回收該對象占用的內存空間以及資源,從而提高內存利用率。
Java中,內存的回收由垃圾回收器(Garbage Collection)自動處理。處理流程:
- 查看堆內存,區分出正在使用的對象和未使用的對象;
- 刪除已經廢棄的對象;
3.6 如何區分一個對象是否任然會被使用呢?
判斷標准——程序持有一個指向對象的引用;若一個對象,不被程序的任何部分持有引用,則判定它的內存是可以被回收的。
GC是通過JVM一個后台的工作線程來完成,它周期性地掃描堆內存來發現程序不再使用的對象。為了判斷對象是否可以被釋放,需要引用計數和對象引用遍歷。引用技術記錄了對特定對象的所有引用數,這意味着,當應用程序創建引用或者引用已經超出聲明周期時,JVM必須適當地增減引用計數。當對象的引用數為0時,便可以進行垃圾收集。
3.7 手動啟動GC
垃圾回收器是JVM自動啟動的,它不受程序代碼的控制,其具體執行的時間也不確定,但是開發者可以利用System.gc()手動強制啟動垃圾回收氣銷毀無用對象。
GC機制還提供了finalize()方法,用於釋放不是通過new操作符創建的對象空間。這種情況一般發生在使用“本地方法(Native Interface)”的情況下,本地方法是一種在Java中調用非Java代碼的方式。
finalize()方法會在GC釋放對象時被執行,即要是我們手動調用了System.gc(),finalize()也會一起執行。
四、實例變量和類變量
4.1 static靜態變量(類變量)
所有對象共享類變量。
程序執行時,類的字節碼被加載到內存,如果該類沒有創建對象,類的實例成員變量不會被分配內存。類中聲明的類變量在該類被加載到內存時,就已經被分配了相應的內存空間,直到程序退出運行才釋放所占用的內存。而如果該類沒有被創建對象,類的實例成員變量不會被分配內存。
從數據操作的角度來看,實例方法既能對類變量進行操作,又能對實例變量進行操作;而類方法只能對類變量進行操作。
實例變量子在申明時如果沒有被賦予初值,將被編譯器初始化為NULL(引用類型),0,或者false,字符變量默認是空。
類變量在類的初始化之前初始化,無論類的實例被創建多少個,類變量只在初始化時被分配一次內存空間。
不同的對象將被分配到不同的堆內存空間
4.2 靜態代碼塊和非靜態代碼塊
static {…}為靜態代碼塊,{…}直接括起來的為非靜態。
凡是static修飾的,都將最先在類被加載時,按排列的位置執行(當然你不能在靜態變量還沒有初始化前就使用它,即你的靜態代碼塊如果在靜態變量的聲明之前,就無法使用,但是可以直接初始化它);
非靜態代碼塊在類初始化創建實例時,將會被提取到類的構造器中執行,而且,非靜態代碼塊會比構造器中的代碼塊先執行。
public class StaticDemo{ static{ name="static-block-1"; System.out.println("static block 1 is over!"); } public static String name="Fancy"; private String mail="myEmail"; static{ System.out.println(name); name="static-block-2"; System.out.println("static block 2 is over!"); } public StaticDemo(){ mail="110@qq.com"; System.out.println("Constructor has been excuted and the name is "+name); } static{ System.out.println(name); name="static-block-3"; System.out.println("static block 3 is over!"); } { mail="119@qq.com"; System.out.println("Non-static block has been excuted"); } public void setName(String name){ this.name=name; System.out.println("SetName is called."); } public static void main(String[] args) { StaticDemo staticDemo=new StaticDemo(); staticDemo.setName("Jay"); } } //output: static block 1 is over! Fancy static block 2 is over! static-block-2 static block 3 is over! Non-static block has been excuted Constructor has been excuted and the name is static-block-3 SetName is called.
4.3 不可變對象
一旦創建就不能被更改。(沒有給外界提供可以修改的操作而已,並沒有多特別)
它的類為不可變類,“不可變”是一種很好的性質,它使得對象的行為是可預測的。它可以被其它對象隨意引用,而不用擔心不可變對象在某個時刻被修改。
優點:
- Java中的所有不可變對象都是線程安全的。
- 構造、測試和使用都很簡單;
- 當用作其它類的屬性時不需要被保護性復制;
- 可以很好地用作Map集合和Set集合的元素;
編寫一個不可變類,就不要提供任何可以修改對象狀態的方法。
