1. 程式人生 > >java創建一個對象時,內存中發生了什麽

java創建一個對象時,內存中發生了什麽

就是 抽象方法 abstract getx 對象共享 鼓勵 事情 指定 更多

JAVA是一種面向對象的語言,它本身具有面向對象的三大特性--封裝,繼承,多態。開發時,我們要記住,屬性是用於存儲數據的。直接被訪問,容易出現安全隱患。所以,類中的屬性通常被私有化,並對外提供公共的訪問方法。這個方法一般有兩個,規範寫法:對於屬性xx,可以使用setXX(),getXX()對其進行操作。

一、類的成員變量存在於堆內存中,隨著對象的產生而存在,消失而消失。局部變量存在於棧內存中,隨著所屬區域的運行而存在,結束而釋放。(著重理解)

二、 創建一個對象都在內存中做了什麽事情?Person p = new Person();

1.先將硬盤上指定位置的Person.class文件加載進內存。

2.執行main方法時,在棧內存中開辟了main方法的空間(壓棧-進棧),然後在main方法的棧區分配了一個變量p。

3.在堆內存中開辟一個實體空間,分配了一個內存首地址值。new

4.在該實體空間中進行屬性的空間分配,並進行了默認初始化。

5.對空間中的屬性進行顯示初始化。

6.進行實體的構造代碼塊初始化。

7.調用該實體對應的構造函數,進行構造 函數初始化。

8.將首地址賦值給p,p變量就引用了該實體。(指向了該對象)

三、this和static詳解

this:代表對象。就是所在函數所屬對象的引用。哪個對象調用了this所在的函數,this就代表哪個對象。就是哪個對象的引用。在定義功能時,如果該功能內部使用到了調用該功能的對象,這時就用this來表示這個對象。this還可以用於構造函數間的調用。調用格式:this(實際參數);

this對象後面跟上.調用的是成員屬性和成員方法(一般方法);

this對象後面跟上()調用的是本類中的對應參數的構造函數。

註意:用this調用構造函數,必須定義在構造函數的第一行。因為構造函數是用於初始化的,所以初始化動作一定要執行。否則編譯失敗。

static:關鍵字是一個修飾符。用於修飾成員(成員變量 和成員函數)。

特點:

1.想要實現對象中的共性數據的對象共享。可以講這個數據進行靜態修飾。

2.被靜態修飾的成員,可以直接被類名所調用。也就是說,靜態的成員多了一種調用方式。類名.靜態方式。

3.靜態隨著類的加載而加載。而且優先於對象存在。

弊端:

1.有些數據是對象特有的數據,是不可以被靜態修飾的。因為那樣的話,特有數據會變成對象的共享數據。這樣對事物的描述就出了問題。所以,在定義靜態時,必須要明確,這個數據是否是被對象所共享的。

2.靜態方法只能訪問靜態成員,不可以訪問非靜態成員。

因為靜態方法加載時,優先於對象存在,所以沒有辦法訪問對象中的成員。

3.靜態方法中不能使用this,super關鍵字。

因為this代表對象,而靜態在時,有可能沒有對象,所以this無法使用。

4.主函數是靜態的。

什麽時候定義靜態成員呢?

成員分兩種:

1.成員變量。(數據共享時靜態化)

該成員變量的數據是否是所有對象都一樣;

如果是,那麽該變量需要被靜態修飾,因為是共享數據。如果不是,那麽就說這是對象的特有數據,要存儲到對象中。

2.成員函數。(方法中沒有調用特有數據時就定義成靜態)

如何判斷成員函數是否需要被靜態修飾呢?

只要參考,該函數內是否訪問了對象中的特有數據。如果有訪問特有數據,那方法不能被靜態修飾。如果沒有訪問過特有數據,那麽這個方法需要被靜態修飾。

靜態的生命周期很長。靜態代碼塊就是一個有靜態關鍵字標示的一個代碼區域。定義在類中。完成類的初始化。靜態代碼塊隨著類的加載而執行,而且只執行一次(new多個對象就只執行一次)。如果和主函數在同一個類中,優先於主函數執行。

主函數的解釋:保證所在類的獨立運行。是程序的入口。被JVM調用。

靜態代碼塊、構造代碼塊、構造函數同時存在時的執行順序:

靜態代碼塊--構造代碼塊--構造函數。

四、再談繼承

繼承是一種連結類的層次模型,並且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。當生成子類對象時,JAVA默認首先調用父類的不帶參構造方法,然後執行該構造方法,生成父類的對象。接下來,再去調用子類的構造方法,生成子類的對象。(要想生成子類的對象,首先需要生成父類的對象,沒有父類對象就沒有子類對象。)
如果子類使用super()顯式調用父類的某個構造方法,那麽在執行的時候就會尋找與super()所對應的構造方法而不會再去尋找父類的不帶參數的構造方法。與this一樣,super也必須要作為構造方法的第一條執行語句,前面不能有其他可執行語句。

當兩個方法 形成重寫關系時,可以在子類方法中通過super.run()形式調用父類的run()方法,其中super.run()不必放在第一行語句,因此此時父類對象已經構造完畢,先調用父類的run()方法還是先調用子類的run()方法是根據程序的邏輯決定的。

方法的覆蓋(重寫)

重寫的要求:子類覆蓋方法和父類被覆蓋方法的方法返回類型,方法名稱,參數列表必須相同;子類覆蓋方法的訪問權限必須大於等於父類的方法的訪問權限;方法覆蓋只能存在於子類和父類之間;子類覆蓋方法不能比父類被覆蓋方法拋出更多異常;

方法重寫與方法重載之間的關系:重載發生在同一個類內部的兩個或多個方法。重寫發生在父類與子類之間。

final關鍵字在繼承中的使用,final可以用於以下四個地方:

1.定義變量,包括靜態的和非靜態的。

如果final修飾的是一個基本類型,就表示這個變量被賦予的值是不可變的,即它是個常量;如果final修飾的是一個對象,就表示這個變量被賦予的引用是不可變的,不可改變的只是這個變量所保存的引用,並不是這個引用所指向的對象,其實更貼切的表述final的含義的描述,那就是,如果一個變量或方法參數被final修飾,就表示它只能被賦值一次,但是Java虛擬機為變量設定的默認值不記作一次賦值。

被final修飾的變量必須被初始化。初始化的方式 有以下幾種:

1.在定義的時候初始化

2.在初始化塊中初始化

3.在類的構造器中初始化

4.靜態變量也可以再靜態初始化塊中初始化。

1>定義方法。

當final用來定義一個方法時,它表示這個方法不可以被子類重寫,但是它這不影響它被子類繼承。

2>定義類

由於final類不允許被繼承,編譯器在處理時把它所有的方法當作final的,因此final類比普通類擁有更高的效率。

關於繼承的幾點註意:

a.父類有的,子類也有

b.父類沒有的,子類可以增加

c.父類有的,子類可以改變

d.構造方法不能被繼承

e.方法和屬性可以被繼承

f.子類的構造方法隱式的調用父類的不帶參數的構造方法

g.當父類沒有不帶參數的構造方法時,子類需要使用super來顯式地調用父類的構造方法,super指的是對父類的引用。

h.super關鍵字必須是構造方法中的第一行語句。

五、多態

多態的意思就是父類的引用可以指向子類的對象。在一個類中,可以定義多個同名的方法,只要確定它們的參數個數和類型不同,這種現象稱為類的多態。類的多態體現在兩個方面:一是方法的重載上,包括成員方法和構造方法的重載;二是在繼承過程中,方法的重寫。

六、抽象

使用abstract關鍵字所修飾的類叫做抽象類。抽象方法需要定義在抽象類中。

七、接口

JAVA語言不支持一個類有多個直接的父類,但現實例子中,又有很多類似於多繼承的例子。JAVA中不可以多繼承,但可以實現(implements)多個接口,間接地實現了多繼承。

八、比較抽象類與接口

相同點:

1.代表系統的抽象層,當一個系統使用一顆繼承樹上的類時,應該盡量把引用變量聲明為 繼承樹的上層抽象類型,這樣可以提高兩個系統之間的送耦合。

2.都不能被實例化

3.都包含抽象方法,這些抽象方法用於描述系統能提供哪些服務,但不提供具體的實現。

不同點:

1. 在抽象類中可以為部分方法提供默認的實現,從而避免在子類中重復實現它們,這是抽象類的優勢,但這一優勢限制了多繼承,而接口中只能包含抽象方法.由於在抽象類中允許加入具體方法,因此擴展抽象類的功能,即向抽象類中添加具體方法,不會對它的子類造成影響,而對於接口,一旦接口被公布,就必須非常穩定,因為隨意在接口中添加抽象方法,會影響到所有的實現,這些實現類要麽實現新增的抽象方法,要麽聲明為抽象類。

2.一個類只能繼承一個直接的父類,這個父類可能是抽象類,但一個類可以實現多個接口,這是接口的優勢,但這一優勢是以不允許為任何方法提供實現為代價的。當子類覆蓋父類的實例方法或隱藏父類的成員變量及靜態方法時,JAVA虛擬機采用不同的綁定規則, 假如還允許一個類有多個直接的父類,那麽會使綁定規則更加復雜。因此,為了簡化系統結構設計和動態綁定機制,JAVA語言禁止多重繼承。一個類即時有多個接口,也不會增加JAVA虛擬機進行動態綁定的復雜度,因為JAVA虛擬機永遠不會把方法與接口綁定,而只會把方法與它的實現類綁定,使用接口和抽象類的總體原則。

java創建一個對象時,內存中發生了什麽