天天看點

黑馬程式員--靜态,單例模式以及繼承

Static 關鍵字

靜态:static是一個修飾符,用于修飾成員(成員變量,成員函數)。

當成員被靜态修飾後,就多了一個調用方式,除了可以被對象調用外,還可以直接被類名調用。(類名.靜态成員)System.out.println(Person.country); 直接被調用

static特點:

1.随着類的加載而加載(也就是說,靜态會随着類的消失而消失。說明它的生命周期最長)

2.優先于對象存在

明确一點:靜态是先存在的。對象是後存在的

3.被所有的對象所共享

4.可以直接被類名所調用

String name;成員變量,執行個體變量

static String country = “cn”;靜态的成員變量,類變量。

執行個體變量和類變量的差別:

1.存放位置: 類變量随着類的加在而存在于方法區中 執行個體變量随着對象的建立而存在于堆記憶體中

2.生命周期: 類變量生命周期最長,随着類的消失而消失

 執行個體變量的生命周期随着對象的消失而消失

靜态的使用注意事項:

1.靜态方法隻能通路靜态成員 非靜态方法既可以通路靜态也可以通路非靜态

2.靜态方法中不可以定義this,super關鍵字。因為靜态優先于對象存在,是以靜态方法中不可以出現this。

3.主函數是靜态的

靜态有利有弊 

利處:對對象的共享資料進行單獨空間的存儲,節省空間。沒有必要每個對象中都存儲一份。

可以直接被類名調用

弊端:生命周期過長。

      通路出現局限性。(靜态雖好,隻能通路靜态)

主函數:是一個特殊的函數,作為程式的入口可以被jvm調用。

主函數的定義:

public :代表着該函數的通路權限是最大的。

static:代表着主函數随着類的加載就已經存在了。

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

main:不是關鍵字。但是是一個特殊的單詞,可以被jvm識别。

函數的參數(String[ ] args):函數的參數,參數類型是一個數組,該數組中的元素是字元串,字元串的類型是數組。

主函數是固定格式的:jvm識别。Jvm在調用主函數時,傳入的是new String[0];

什麼時候使用靜态:

要從兩方面下手:因為靜态修飾的内用有成員變量和成員函數。

 class Day6_1 

{

public static void main(String[] args) 

{

System.out.println(Person.country);

//Person p = new Person(20);

//p.test();

Person.show();//可以直接調用靜态方法

}

}

class Person

{

int age;

static String country = "CN";

Person(int age)

{

this.age = age;

System.out.println(age+"    ..    "+country);

}

public static void show()

{

//test();   錯誤是因為靜态中調用非靜态的方法 導緻找不到test方法

System.out.println("show()中的:"+country);

}

public void test()

{

System.out.println("it just a test");

}

}

什麼時候定義靜态變量(類變量)呢?

當對象中出現共享資料時,該資料被靜态所修飾。

對象中的特有資料要定義成非靜态,存在于堆記憶體中。

什麼時候定有靜态函數呢?

當功能内部沒有通路到非靜态資料(對象的特有資料),那麼該功能可以定義成靜态的。

靜态的應用:

每一個應用程式中都有共性的功能,可以将這些功能進行抽取,獨立封裝。

以便複用。

靜态代碼塊

格式:

static 

{

靜态代碼塊中執行的語句。

}

特點:随着類的執行而執行,隻執行一次。用于給類進行初始化。并優先于主函數

(構造代碼塊

格式

{

System.out.println(“a”);

}

靜态代碼塊

static 

{

System.out.println(“v”);

}

//靜态代碼塊

class Day6_3 

{

public static void main(String[] args) 

{

new StaticDemo(10);

}

}

class StaticDemo

{

int a = 10;

{

System.out.println("b"+ this.a);//構造代碼塊

}

StaticDemo()

{

System.out.println("c");//空param的構造函數

}

static

{

System.out.println("a" );//靜态代碼塊,最先執行

}

StaticDemo(int a)

{

System.out.println("d");//帶參數的構造函數

}

}

非靜态前面省略this.(this.method();) 靜态前面省略類名.(Person.method();)

設計模式:解決某一類為題最行之有效的方法。

java中23種設計模式:

單例設計模式:解決一個類在類存隻存在一個對象。

想要保證對象唯一。

1.為了避免其他程式過多建立該類對象。先禁止其他程式建立該類對象

2.還為了讓其他程式可以通路到該類對象,隻好在本類中,自定義一個對象。

3.為了友善其他程式對自定義對象的通路,可以對外提供一些通路方式。

 //單例模式 設計方式

class Day6_4 

{

public static void main(String[] args) 

{

System.out.println("Hello World!");

Student a = Student.getInstance();

a.setAge(20);

Student b = Student.getInstance();

System.out.println(b.getAge());//20個對象公用一個函數

}

}

class Student

{

private int age;

public void setAge(int age)

{

this.age = age;

}

public int getAge()

{

return age;

}

private Student(){}//單例模式的3步

private static Student s = new Student();//

public static Student getInstance()//

{

return s;

}

}

class Car

{

private Car(){}

private static Car c = new Car();

public static Car getInstance()

{

return c;

}

}

class Man//餓漢式

{

private Man(){}

private Man m = new Man();

public static Man getInstance()

{

return m;

}

}

class Woman//懶漢式 單例模式的延遲加載

{

private Woman(){}

private Woman w = null;

public static Woman getInstance()

{

if(w == null)

w = new Woman();

return w;

}

}

這三步怎麼用代碼展現呢?

1.講構造函數私有化

2.在類中建立一個本類對象

3.提供一個方法可以擷取到該對象 

繼承:

1.提高了代碼的複用性

2.繼承讓類與類之間産生了關系,有了這個關系,才有了多态的特性。

注意:千萬不要為了擷取其他類的功能,簡化代碼而繼承。

必須是類于類之間有所屬關系才可以繼承。所屬關系 is a。

java語言中:java隻支援單繼承,不支援多繼承。因為多繼承容易帶來安全隐患

當多個父類中定義了相同功能,但功能内容不同時,子類對象不确定運作哪一個

但是java保留了這種機制。并用另一種展現形式來完成表示。多實作。

java支援多層繼承。也就是一個繼承體系

如何使用一個繼承體系中的功能呢?

想要使用體系,先查閱體系父類的描述,因為父類中定義的是該體系中的共性功能。

通過了解共性功能,就可以知道該體系的基本功能。

那麼這個體系已經可以基本使用了

那麼在具體調用是,要建立最子對象,為什麼呢?

一是因為有可能父類不能建立對象,二是建立子類對象可以使用更多功能,包括基本的也包括特有的

簡單一句話:查閱父類功能,建立子類對象使用功能

另外一種關系

聚集:has a

聚合: 

組合

子父類中的函數

當子類出現和父類一模一樣的函數時,當子類對象調用該函數,會運作子類函數的内容,如同父類的函數被覆寫一樣,這種情況是函數的另一個特征:重寫(覆寫)

當子類繼承父類,沿襲了父類的功能到子類中,但是子類雖有該功能,但是功能的内容卻和父類不一緻,這時,沒有必要定義新功能,而是使用覆寫特性,保留父類的功能定義,重寫父類内容。

覆寫:1.子類覆寫父類,必須保證子類權限大于等于父類權限,才可以覆寫,否則,編譯失敗。(public>空白>private)

2.靜态隻能覆寫靜态

重載:隻看同名函數的參數清單。

重寫:子夫類方法要一模一樣。

子父類中的構造函數

在對子類對象進行初始化時,父類的構造函數也會運作,那是因為子類的構造函數預設第一行有一條隐的語句 super();

super():會通路父類中控參數的構造函數,而且子類中所有構造函數的預設第一行都是super();

為什麼子類一定要通路父類中的構造函數?

因為父類中的資料子類可以直接擷取,是以子類對象在建立時,需要先需要先檢視父類是如何對這些資料進行初始化的。是以子類對象初始化時,要先通路一下父類中的構造函數,如果要通路父類中指定的構造函數,可以通過手動定義速super語句的方式來指定。

注意:super語句一定放在子類構造函數的第一行。

//構造函數的繼承 

class Day7_2

{

public static void main(String[] args) 

{

Student s = new Student();

new Student (20);

}

}

class Person

{

Person(int a)

{

System.out.println("zou jibu "+a);

}

}

class Student extends Person

{

Student()

{

//super(); 自動調用父類中空參數的構造函數

super(10);

System.out.println("我是學生啊 ");

}

Student(int a)

{

this();

System.out.println("ccacacacaca"+a);

}

}

子類的的執行個體化過程:

結論:

子類的所有構造函數,預設都會通路父類中空參數的構造函數,因為子類每一個構造函數内的第一行都有一句隐式super();

當父類中沒有空參數的構造函數時,子類必須手動通過super語句形式來通路父類 中的構造函數,當然:子類的構造函數第一行也可以手動指定this語句來通路本類中的構造函數,子類中至少會有一個構造函數會通路父類中的構造函數。