Java基礎7--建構函式--this--static記憶體詳解__java

來源:互聯網
上載者:User
7-1,建構函式-概述

1,特點:

(1)函數名與類名相同。

(2)不用定義傳回值類型。

(3)沒有具體的傳回值。

2,建構函式

建構函式就是構建創造對象是調用的函數。

3,作用

可以給對象進行初始化,即對象一建立裡面就包含一些內容。

4,樣本:

class Person{private String name;private int age;Person(){//定義一個空參建構函式Sop("Person run ...");}public void speak(){Sop(name+"::"+age)}}class Demo {public static void main(String[] args) {Person p = new Person();}}
7-2,預設建構函式

1,建立對象都必須通過建構函式初始化。

2,一個類中如果沒有定義過建構函式,那麼該類中一定會有一個預設的空參建構函式,如果在類中定義指定的建構函式,那麼類中的預設的建構函式就沒有了。

3,建構函式是用來給對象初始化的,沒有初始化的對象絕對不能用。

  7-3,一般函數和建構函式的區別

區別:

(1)建構函式:對象建立時,就會調用與之對應的建構函式,對對象進行初始化。

一般函數:對象建立後,需要函數功能時才使用。

(2)建構函式:對象建立時會調用,只調用一次。

一般函數:對象建立後,可以被調用多次。

  7-4,建構函式-重載

1,什麼時候定義建構函式。

在描述事物時,該事物已存在就具備一些內容,這些內容都定義在建構函式中。

2,重載:函數名相同,參數列表不同。

樣本:

class Person {private String name;private int age;Person() {//函數1name = "baby";age = 1;}Person(String n) {//函數2name = n;}Person(String n,int a) {//函數3name = n;age = a;}public static void main(String[] args) {Person p1 = new Person();//調用函數1Person p2 = new Person("zhangsan");//調用函數2Person p3 = new Person("lisi",20);//調用函數3}}

3,注意,形如:

Person(int a,String n);

Person(String n,int a);

的兩個函數是重載形式。

  7-5,建構函式-記憶體配置圖解

Person p = newPerson("lisi",20);

p.speak();

以上兩句在記憶體中表示為:

步驟:

(1)從main函數開始,main函數進棧,局部變數p進棧。

(2)在堆中建立p的實體,分配地址,給變數預設初始化。

(3) new Person("lisi",20);調用了Person的建構函式,把實參傳入,Person(String,int)函數進棧。

(4)把傳入的參數賦值。

(5) Person p = newPerson("lisi",20);執行完畢,把地址值賦給棧中的p,p指向堆中的實體。

(6)Person(String,int)執行完畢,彈棧。

(7)p.speak();調用speak方法,speak()進棧。

(8)執行speak中的輸出語句。

(9)speak()執行完畢,彈棧。

  7-6,建構函式-細節

1,建構函式:Person(String n){name=n;}

與一般函數public void setName(String n){name= n;}

不衝突,建構函式在建立對象的一開始的時候就賦值,只調用一次,值不能再改,一般函數可以調用多次,可以在後期對值進行改變。

2,建構函式中可以調用一般函數,一般函數中一般不調用建構函式,建構函式是用來初始化對象的,若非要在一般函數中調用建構函式,需要新建立一個對象。

3,Person(){}與voidPerson(){}不一樣,前者為建構函式,後者為一般函數,建構函式加上修飾符就變成了一般函數,一般函數可以與類名相同。

4,若Person類中已經定義了建構函式,這時預設建構函式已經被覆蓋,若只有一個void Person(){},而main中有Person p = new Person();則編譯失敗,因為voidPerson(){}是一個一般函數主函數無法找到Person(){}給對象初始化,所以報錯誤。

5,建構函式中是有return語句的,return語句是用來結束函數用的,若return後面還有語句,則編譯報錯,因為return後面的語句不會被執行到。

  7-7,關鍵字-this使用情境-記憶體配置圖解

1,this表示這個對象的***,比如this.name表示這個對象的name屬性。

2,情境:當成員變數和局部變數重名,可以用關鍵字this來區分。

3,this:代表對象,代表當前對象。

This就是所在函數所屬對象的引用。

簡單說:哪個對象調用了this所在的函數,this就代表哪個對象。

例如:

class Person {private String name;Person(String name) {this.name = name;}public static void main(String[] args) {Person p = new Person("zhangsan");}}

上例中的this指代的就是p對象,this.name指向的是堆記憶體中這個對象的name屬性。

 

4,記憶體配置圖解:

class Person{private String name;private int age;Person(String name) {this.name = name;}public void speak() {sop(name + ":" + age);}}class ThisDemo {public static void main(String[] args) {Person p = new Person("zhangsan");p.speak();}}

步驟:

(1)從main函數開始,main函數進棧,局部變數p進棧。

(2) new Person("zhangsan");在堆記憶體中開闢空間,分配地址,name和age變數進入堆中的對象,預設初始化為null和0。

(3)Person(name)建構函式進棧。

(4)把"zhangsan"傳入,賦給局部變數name。

(5)函數進入棧會自動帶有一個this引用,因為是p調用Person(),所以this的值為新建立對象的地址0X0078。

(6)Person中的this指向堆中的0X0078。

(7)this.name指向的是0X0078中的name,給此name賦值為"zhangsan"。

(8)Person(name)執行完畢,彈棧。

(9)p = newPerson("zhangsan");把0X0078賦給main中的p。

(10)speak()函數進棧,並內建一個this引用。

(11)p.speak();p調用speak,把p的地址給this。

(12)執行完輸出彈棧。

說明:其實每個函數中都內建一個this,只不過不重名時不用區分,重名時用this區分開來,this都指代當前對象的地址。

如:sop(name + age);的標準寫法是:sop(this.name + this.age);

  7-8,this關鍵字使用情境及細節

1,在建構函式中調用建構函式

Person(String name) {this.name = name;}Person(String name,int age) {this(name);//this代表對象,給對象初始化,調用的是同類中上面的那個建構函式this.age = age;}

this也可以用於在建構函式中調用其他建構函式。

注意:只能定義在建構函式的第一行,因為初始化動作要先執行。這說Java的文法,不這樣寫會報錯。

2,範例程式碼記憶體配置圖解:

class Person{private String name;private int age;Person() {name = "baby";age = 1;sop("Person run...");}Person(String name) {this.name = name;}Person(String name,int age) {this(name);this.age = age;}public void speak() {sop(this.name + "-" + this.age);}}class ThisDemo {public static void main(String[] args) {Person p = new Person("zhangsan",30);p.speak();}}

步驟:

(1)從main函數開始,main函數進棧,局部變數p進棧。

(2) newPerson("zhangsan",30);在堆中開闢記憶體空間,分配地址,name和age預設初始化為null和0。

(3)傳參數,Person(name,age)進棧,內建this引用,指向堆記憶體0X0067,局部變數name,age傳參數賦值。

(4)this(name)調用Person(name),內建this引用,指向堆記憶體0X0067,局部變數name賦值。

(5)this.name = name;指Person(name)中的name賦給堆中實體的成員變數name。

(6)Person(name)運行完彈棧。

(7)執行Person(name,age)中的this.age=age;給堆中的成員變數賦值。

(8)Person(name,age)運行完彈棧。

(9)把0X0067賦給main中的p。

 

3,避免程式出現以下情況:

class Person{private String name;private int age;Person() {this("haha");//2.調用Person(name)   4.調用Person(name)....name = "baby";age = 1;sop("Person run...");}Person(String name) {this();//3.調用Person()    5.調用Person()....this.name = name;}public static void main(String[] args) {new Person();  //1.給Person初始化,調用Person()}}

上述代碼是Person()和Person(name)之間的來回調用,導致棧記憶體溢出。

  7-9,this應用

程式:判斷是否是同齡人

public Person {private String name;private int age;Person(){}Person(String name,int age) {this.name = name;this.age = age;}public static void main(String[] args) {Person p1 = new Person("aa",20);Person p2 = new Person("bb",30);boolean b = p1.compare(p2);System.out.println(b);}public static boolean compare(Person p) {/*方法一if(this.age == p.age) {return true;} else {return false;}*///方法二return this.age == p.age;}}
7-10,static關鍵字-資料共用

用static修飾的資料是可以被共用的資料。

如:String name;

    staticString country = “cn”;

由於每個人的name是不一樣的,但是country一樣,都是cn,如果不將cn定義為static的,當每建立一個對象,每個對象中都會有cn,浪費記憶體空間。

可以把country定義為static的,這樣所有的對象都可以共用這個資料,哪個對象需要,調用即可。

  7-11,static的特點

1,用static修飾的成員先於對象存在,存在於類中,可以用類名直接調用。例如Person.country;

2,不能所有都定義成static的,有些可以被共用,但是有一些是每個對象特有的,不能被共用。

3,特點:

(1)static是一個修飾符,用於修飾成員。

(2)static修飾的成員被所有的對象所共用。

(3)static優先於對象存在,因為static修飾的成員隨著類的載入就已經存在了。

(4)static修飾的成員多了一種調用方式,可以直接被類名調用,格式:類名.靜態成員。

(5)static修飾的資料是共用資料,對象中儲存的是特有資料。

  7-12,成員變數和靜態變數的區別

class person{String name; //成員變數,執行個體變數static String country = "cn"; //靜態變數,類變數......}

區別:

(1)兩個變數的生命週期不同。

成員變數:隨著對象的建立而存在,隨著對象的被回收而釋放。

靜態變數:隨著類的載入而存在,隨著類的消失而消失。

(2)調用方式不同。

成員變數:只能被對象調用。

靜態變數:可以被對象調用,也可以被類名調用。

(3)別名不同。

成員變數:也成為執行個體變數。

靜態變數:也成為類變數。

(4)資料存放區位置不同。

成員變數:資料存放區在堆記憶體的對象中,所以也叫對象的特有資料。

靜態變數:資料存放在方法區(共用資料區)的靜態區,所以也叫對象的共用資料。

  7-13,static的注意事項

1,注意事項:

(1)靜態方法只能訪問靜態成員。(非靜態既可以訪問靜態,又可以訪問非靜態)。

(2)靜態方法中不可以使用this或者super關鍵字。(因為靜態先載入,沒有對象,不可以用this)

(3)主函數是靜態。

2,main()是靜態,不可以直接調用非靜態方法,可以通過建立對象調用。

非靜態變數在使用的時候前面省略了this,靜態變數在使用時前面省略的是類名。

class Person{public static void main(String[] args) {run();//run必須是靜態,否則報錯}public static void run() {System.out.println("run...");}}
7-14,main函數詳解

1,public static void main(String[] args)

主函數的特殊之處:

(1)格式是固定的。

(2)被JVM識別和調用。

public : 因為許可權必須最大。

static : 程式從main函數開始執行,不需要對象調用main函數,其實是直接被主函數的類名調用的,所以必須是靜態

例如要運行Person類,一般我們在命令列輸入java Person執行,其實JVM調用的是java Person.main。

void : 主函數沒有具體的傳回值。

main : 函數名,不是關鍵字,只是一個JVM識別的固定的名稱。

String[] args : 這是主函數的參數列表,是一個字串數群組類型的參數。

 

2,調用main函數的時候也要向String[]args傳遞實參,是由JVM傳遞的。

可以使用System.out.println(args);驗證,結果為:

[Ljava.lang.String@c17164

可以說明是一個String的數組。

預設這個數組的長度是0。

JVM向String[] args傳遞的是newString[0]。

 

3,我們在運行程式的時候,可以給main函數傳遞參數,程式中的任何結果最終都要轉成字串顯示在螢幕上。

 

4,運行程式時傳值,命令列中,在使用java命令時傳遞。

java Person haha hehe xixi 用空格分隔,作為數組中的元素傳遞給args。

 

5,String[] 中的args可以變化,不是固定的,args是arguments的簡寫。

 

6,public static void main(String[] args)

 

    publicstatic void main(int[] x)

二者不衝突,是重載的形式。

如果將後面的int[] x變為String[]x,則衝突。

  7-15,static關鍵字-程式記憶體詳解

以下面程式為例:

class Person{private String name;private int age;static String country = "cn";public Person(String name,int age) {this.name = name;this.age = age;}public void show() {System.out.println(Person.country + ":" + this.name + ":" + this.age);}public static void method() {System.out.println(Person.country);}}class StaticDemo{public static void main(String[] args) {Person.method();Person p = new Person("Java",20);p.show();}}

當在命令列用java StaticDemo運行這個程式時,這個類就會被載入進記憶體,需要進行空間的開闢,進入方法區,方法區分為靜態區和非靜態區兩個地區。

步驟:

(1)當執行StaticDemo時,StaticDemo類就載入進記憶體,並開闢空間,預設建構函式StaticDemo()也載入進記憶體,載入進記憶體的方法區的非靜態區。

(2)接著main函數也進入記憶體,進入記憶體方法區的靜態區(靜態區的方法和非靜態區的方法都是被共用的,唯一的不同是封裝的資料不同),非靜態區的所有成員都有一個this所屬,因為非靜態區的方法都被對象調用,而靜態區的方法都是所屬自己的類名。

(3)當java StaticDemo,斷行符號時,函數載入完畢,StaticDemo直接用類名調用主函數,這時main函數進棧,main函數中的所有代碼都在靜態區的static main()中。

(4)運行Person.method();時用到了Person類,這時Person載入,這時JVM會在classpath下找是否有Person.class檔案,若沒有則在當前預設目錄下找,找到後就會將Person.class載入進記憶體,Person類中的建構函式Person(name,age)以及其中的代碼和void show()方法以及其中的代碼都載入進非靜態區;Person中的靜態方法method()和靜態變數country載入進靜態區,country預設初始化為null,因為給他賦值為”cn”,所以馬上顯示初始化為cn,現在country=cn。

(5)Person.method();是用類名調用,說明method()是static的,調用時直接在靜態區的Person類中找method方法,找到後,method方法進棧,注意此方法是沒有this所屬的,只有非靜態區持有this。

說明:method方法在方法區,為何進棧執行。

因為方法區是方法的存放區,也叫方法表,所有的方法都在這裡。而棧是運行區,因為方法內可能會有局部變數,局部變數是需要在棧記憶體中開闢空間儲存的,而且運行完局部變數要釋放,所以要到棧中運行。但System.out.println()方法不會進棧執行,這個方法是用於輸出的,沒有局部變數。棧中只存放方法的局部變數,進棧後method方法開始執行,由於只有一個System.out.println()方法,所以直接到靜態區的method中找到System.out.println()執行,有局部變數時才在棧中開闢空間。

method方法的sop中有Person.country,這時直接從靜態區的Person類中找到country,並且輸出對應的值。

(6)method方法運行完畢,彈棧。

(7)執行Person p = new Person("Java",20);局部變數p進棧。

(8)在堆中為p對象開闢空間,分配地址,成員變數name,age進入記憶體,並預設初始化為null和0,然後執行建構函式初始化,此時建構函式Person(name,age)進棧,給對象中的資料初始化,函數中持有一個this引用,並且值為0X0078,因為0X0078的對象在調用它,局部變數name被賦值為Java,age被賦值為20,因為Person(name,age)進棧並且初始化完畢,就開始執行方法區中的代碼(Person(name,age)方法的代碼),因此this代表0X0078,所以通過這個地址找到堆中的name並賦值為Java,將20賦值給age。

(9)Person(name,age)運行完畢,彈棧。

(10)new Person("Java",20);初始化完畢,把地址0X0078賦給p,p指向堆記憶體。

(11)p.show();show方法進棧,因為show是非靜態,內建一個this引用,this指向0X0078。show中有一個sop,sop中的country在編譯完後已經有類名所屬,直接在靜態區中的Person類中調用,name和age前邊都省略了this,this是show中的this,代表0X0078,所以列印0X0078中的name和age,即Java和20,然後輸出。

(12)輸出完畢,show方法執行完畢,彈棧。

(13)執行到main函數中的return語句,main函數結束,main函數彈棧,程式執行結束,JVM結束。 7-16,static關鍵字什麼時候用。

靜態什麼時候用。

1,靜態變數

當分析對象中所具備的成員變數的值都是相同的,這時這個成員就可以被靜態修飾。只要資料在對象中都是不同的,就是對象的特有資料,必須儲存在對象中,是非靜態。如果是相同的資料,對象不需要做修改,只需要使用即可,不需要儲存在對象中,定義成靜態。

2,靜態函數

函數是否用靜態修飾,就參考一點,就是該函數的功能是否有訪問到對象中的特有資料。簡單點說,從原始碼看,該功能是否需要訪問到非靜態成員變數,如果需要,該功能就是非靜態,如果不需要,就可以將該功能定義成靜態。當然,也可以定義成非靜態,但是非靜態需要被對象調用,而建立對象調用非靜態沒有訪問特有資料的方法,該對象的建立是沒有意義的。

  7-17,static靜態代碼塊

靜態代碼塊是隨著類的載入而執行的,而且從這個類載入到消亡,只執行一次。

作用:可以給類進行初始化。

格式:

class Person {static {...}}

應用:不是所有的類都是通過建構函式初始化的,如果一個類中的方法全是靜態,那就不需要建立對象,不建立對象就沒有new的過程,不new就無法對建構函式初始化,而這時就可以用靜態代碼塊對類進行初始化。

  7-18,構造代碼塊

1,構造代碼塊定義在類中,它可以給所有對象進行初始化,也就是說,每次new一個對象的時候,它都會執行。

2,構造代碼塊與局部代碼塊的區別

構造代碼塊定義在類中,局部代碼塊定義在方法體中。

3,格式:

class Person {{//構造代碼塊...//抽取出所有對象共性的初始化內容,定義在這裡。//每次建立一個Person對象,這個代碼塊都會執行。}...}

4,程式執行順序

靜態代碼塊-->構造代碼塊-->建構函式

  7-19,總結

1,被static修飾的成員具備以下特點:

(1)隨著類的載入而載入。

(2)優先於對象而存在。

(3)被所有對象共用。

(4)可以直接被類名調用。

 

2,static使用時注意:

(1)靜態方法只能訪問靜態成員。

(2)靜態方法中不可以寫this,super關鍵字。

(3)主函數是靜態。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.