1. 程式人生 > >java基礎-初級(二)【面向物件與類】

java基礎-初級(二)【面向物件與類】

目錄

 

2、面向物件與類

2.1  面向物件思想

2.2  類與物件

2.3  成員和區域性變數

2.4  匿名物件

2.5  類的訪問許可權修飾符

2.6  static關鍵字-靜態域、靜態方法、靜態程式碼塊

2.7  類和物件初始化順序

2.8  main方法


2、面向物件與類

2.1 面向物件思想:

面向物件是將物件作為基本程式結構為單位的程式設計。例如,我們去超市買東西,收銀員小姐姐會問你有沒有會員卡,刷卡還是現金,掃描食品的一系列動作稱之為一個面向過程。當你將小姐姐看成一個物件時,將她的動作作為物件呼叫的方法,就是面向物件的思想了。

2.2 類與物件

類:類是構造物件的模板或者藍圖。由類構造物件的過程叫做建立類的例項。

類與類之間的幾種關係:

(1)繼承 (2)實現 (3)依賴(4)關聯(5)聚合(6)組合

耦合關係   實現<繼承<組合<聚合<關聯<依賴

物件:物件是將包含一些屬性組成的例項。要想使用OOP(面向物件),清楚以下三個主要特性

1、物件的行為:可以對物件施加哪些操作,或者施加哪些方法?

2、物件的狀態:施加方法時,物件如何響應

3、物件標識:如何辨別具有相同行為和狀態的不同物件

2.3 成員和區域性變數

成員變數:在類體中定義的變數為成員變數,作用範圍(scope)是整個類,只要在這個類中都可以訪問到它。

區域性變數:在方法或方法中的程式碼塊中定義的變數為區域性變數,作用範圍是{}內。區域性變數建立的時候必須初始化值,否則編譯報錯。

2.4  匿名物件

匿名物件就是建立一個物件的時候沒有賦予名字,例如new Student()就是一個匿名物件。

使用:一般在物件只調用方法一次的時候建立。例如new Student().run();也可以在方法中作為傳參的作用。

(5)面向物件的三大特性 

  1. 成員變數儲存在堆中(方法區中的靜態區),區域性變數存放在棧中
  2. 生命週期不同,區域性變數生成的銷燬在方法塊中開始和結束的時候,成員變數隨著物件的建立和消失變化。
  3. 初始化不同,成員變數不必須初始化,區域性變數必須初始化。
  4. 位置不同,成員變數在方法的外面,類的裡面。區域性變數在方法的裡面。
  1. 封裝:就是把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者物件操作,對不可信的進行資訊隱藏。
  2. 繼承:讓某個類去繼承其他類的屬性和方法,這個類擁有了父類的屬性和方法。通過繼承的類叫做子類或基類,被繼承的類叫做父類或超類。繼承的方式有兩種,實現繼承和介面繼承。實現繼承指的是子類無需編碼即可使用父類的屬性或方法,介面實現指的是子類只是繼承類屬性和方法的名稱,但是需要提供實現的能力。
  3. 多型:多型就是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定。

實現多型的三個必要條件:繼承、重寫、向上轉型。

 

 2.5 類的訪問許可權修飾符

修飾詞 本類 同包的類 繼承類 其他類
private × × ×
protected ×
public
無(預設) × ×

2.6 static關鍵字-靜態域、靜態方法、靜態程式碼塊

(1)靜態域

如果有資料需要被共享給所有物件使用時,那麼就可以使用static修飾。

如果是類中的域定義為static,這個域屬於這個類而不是這個類的例項。

 

注意:static不能修飾區域性變數

(2)靜態方法:靜態方法是一種不能向物件實施操作的方法。可以認為靜態方法是沒有this引數的方法(在一個非靜態的方法中,this引數表示這個方法的隱式引數),所以不能在靜態方法中訪問非靜態成員方法和非靜態成員變數,但是在非靜態成員方法中是可以訪問靜態成員方法/變數的。

(3)靜態塊:靜態程式碼塊在類載入到JVM時執行,且只被執行一次,這些程式碼不需要例項化類就能夠被調,並且程式碼是主動執行的。


class  Student {
    private int age;
    private  static String school="北京大學";
    private final static  Student student2 = new Student(30);
    /*靜態程式碼塊*/
    static{
        System.out.println("靜態程式碼塊載入!");
        Student student = new Student();
    }
    /*非靜態程式碼塊*/
    {  System.out.println("非靜態程式碼塊載入");
        getSchool();
    }

    /*建構函式*/
    private Student(){
        System.out.println("建立student例項");
    }
    /*建構函式*/
    public Student(int age){
        System.out.println("建立student例項,age="+age);
    }

    /*靜態函式*/
    private static String getSchool(){
        System.out.println("student的大學是"+school);
        return school;
    }

    public static void main(String[] args) {


    }

執行結果: 

非靜態程式碼塊載入
student的大學是北京大學
建立student例項,age=30
靜態程式碼塊載入!
非靜態程式碼塊載入
student的大學是北京大學
建立student例項

靜態常量和靜態程式碼塊虛擬機器一載入就會執行,並且是按照順序執行,這就是為什麼上面的執行結果的原因。

程式碼的執行順序!!

主調類的靜態程式碼塊 -> 物件父類的靜態程式碼塊 -> 物件的靜態程式碼塊 -> 物件父類的非靜態程式碼塊 -> 物件父類的建構函式 -> 物件的非靜態程式碼塊 -> 物件的建構函式

2.7 類和物件初始化順序

下面看一下類和物件的載入過程(重點!!!

類載入過程:

① JVM啟動,載入所需要的class檔案
② JVM載入class檔案時,會把所有的靜態內容(靜態成員變數、靜態方法、靜態程式碼塊)都先載入到方法區中的靜態區中。
③ 靜態載入完成之後,JVM開始給所有的靜態成員變數預設初始化,靜態成員變數開闢空間。
④ 當給類中的所有靜態成員變數預設初始化完成,開始按照程式碼的順序依次執行(遇到靜態程式碼塊就執行,遇到靜態成員變數就顯示初始化)
⑤ 靜態都執行完畢,類才徹底載入完成

物件的載入過程:

① 當類載入完成,使用new關鍵字建立物件,在堆給物件分配記憶體空間
② 給物件所屬的類的非靜態成員變數分配空間並進行預設初始化
③ 在JVM自動調取建構函式時先執行隱式三步
  • super()區訪問父類構造,對父類進行初始化
  • 給非靜態成員變數進行顯示賦值
  • 執行構造程式碼塊

④ 在執行建構函式中的其它程式碼
⑤ 建構函式執行完畢,物件建立完成。

下面看一下什麼時候載入類?也就是載入類的條件,何時觸發初始化

  1. 為一個型別建立一個新的物件例項時(比如new、反射、序列化)
  2. 呼叫一個型別的靜態方法時(即在位元組碼中執行invokestatic指令)
  3. 呼叫一個型別或介面的靜態欄位,或者對這些靜態欄位執行賦值操作時(即在位元組碼中,執行getstatic或者putstatic指令),不過用final修飾的靜態欄位除外,它被初始化為一個編譯時常量表達式
  4. 呼叫JavaAPI中的反射方法時(比如呼叫java.lang.Class中的方法,或者java.lang.reflect包中其他類的方法)
  5. 初始化一個類的派生類時(Java虛擬機器規範明確要求初始化一個類時,它的超類必須提前完成初始化操作,介面例外)
  6. JVM啟動包含main方法的啟動類時。

下面就是使用final的靜態常量不觸發類的載入初始化例子:

public class StaticVar {
    static {
        System.out.println("Class4Load loaded...");
    }

    public static String VAR = "VAR_In_LOAD";

    public static final String FIANL_VAR = "FIANL_VAR_In_LOAD";
}
public class StaticVarLoadTest {

    public static void main(String[] args) {
        System.out.println("StaticVarLoadTest");
        printStaticVar();
    }

    private static void printStaticVar() {
       // System.out.println(StaticVar.VAR);
        System.out.println(StaticVar.FIANL_VAR);
    }

}

結果:StaticVarLoadTest
     FIANL_VAR_In_LOAD

 2.8 main方法

 main()方法的宣告為:public static void main(String args[])。必須這麼定義,這是Java的規範。

下面是引用的一些面試題:

一、main方法是做什麼用的?

main方法是java程式的入口方法,JVM在執行的時候會首先查詢main方法。

二、不用main方法如何執行一個java類?

沒有main方法我們不能執行java類,在java7之前,你可以通過靜態初始化來執行java類,但是從java7開始就行不通了。

三、main方法是如何傳遞引數的?傳遞的引數型別是什麼?能不能改變該引數型別?

通過String陣列,不能改變該引數型別。

四、main方法為什麼是靜態的?能不能改為非靜態?

main方法一定是靜態的,如果不是靜態的,那麼JVM在呼叫main方法時就要例項化main方法所在的類。main方法不能改為非靜態的,main方法必須宣告為靜態的,這樣JVM才可以在呼叫main方法時而無需去例項化它所在的類,如果從main方法中去掉static宣告,雖然可以編譯成功,但在執行時會導致程式執行失敗,因為JVM在例項化時,會呼叫其類的建構函式,如果這個類的建構函式有引數,那麼就會出現歧義。

五、main方法能被過載嗎?

可以的。一個java類可以有任意數量的main方法。

六、main方法能被重寫嗎?

不可以。在java中靜態方法編譯時會編譯在一起,main方法是靜態方法,所以不能重寫。

七、main方法的返回值型別是什麼?能不能改變?

void,不能改變。

八、main方法的作用域用什麼修飾?能不能改變?

public,不能改變,如果main方法不用public修飾,雖然編譯也能成功,但是在執行時會失敗,因為JVM找不到main方法。

九、main方法可以執行緒同步嗎?

可以。synchronized允許使用在main方法的宣告中。

十、main方法可以終結嗎?

可以。