1. 程式人生 > >Java中的組織形式、類與物件、靜態的static關鍵字、最終的final關鍵字、方法傳參方式、遞迴(階乘、斐波那契數列、漢諾塔)

Java中的組織形式、類與物件、靜態的static關鍵字、最終的final關鍵字、方法傳參方式、遞迴(階乘、斐波那契數列、漢諾塔)

Java程式的組織形式

Java程式需要把程式碼以類的形式組織起來,然後被Java編譯器編譯,再被JVM執行。Java程式是以類的結構為基礎的。

  • Java程式的基本要素
  1. 識別符號
    識別符號命名規範
  2. 關鍵字(保留字)
    關鍵字(保留字)具有專門的意義和用途,不能作為使用者自定義識別符號。
  3. 註釋
    //註釋本行
    /*註釋區間*/
    /***文件註釋*/
    文件註釋可以寫入HTML說明文件。

Java程式的基本結構

Java程式的結構以類為基礎,一個Java檔案的原始檔中可包含多個類,但是這個類中只能有一個公共類,並且該公共類的命名與源程式的檔名完全一致(所以檔名稱同類名稱一樣不能以數字開頭且符合命名原則)。類體現了面向物件的基本思想的封裝。封裝:隱藏類的實現的細節,對外提供可以改變不可外界直接訪問的成員變數的介面以實現對成員變數的操作。
類是面向物件的程式設計的重要單位。類是對相同或者類似的事物間共性的一種抽象。類是資料和對資料進行操作的方法的集合體,這個集合體被看作是一個不可分割的有機整體,類是一個新的資料型別


通過這個資料型別定義多個變數,這些變數就是物件。物件是類的例項化。可以理解為類是建立物件的一種模板。
任何事物都是物件,對具有相同或相似的物件的特性進行抽象形成類。

定義類的一般格式

	<訪問許可權修飾符> <狀態修飾符> class <類名稱> {
	}

注意:當前學習階段,類的訪問許可權修飾符只能是public或者預設修飾符
訪問許可權修飾符也可以修飾類的成員變數和類的方法變數
類中包含了屬性(成員變數)和功能(成員方法)
成員變數定義在類中且方法外。
成員方法中的引數為區域性變數,隨著方法執行的結束而釋放空間,當形式引數為基本資料型別時,實參對應的結果(實參的複製本)參與運算,不能直接改變實參的值,而當形參型別為類型別(也就是指標時,實參傳遞的實際上是指標的值。)所以可以改變實際引數的值。

  • 許可權修飾符及其作用
    訪問許可權修飾符作用是說明宣告的內容(類、類的成員變數、類的方法變數)的訪問許可權。合理使用訪問修飾符可以降低類的耦合度,從而降低整個專案的複雜度,便於整個專案的開發和維護。
訪問許可權修飾符 含義 作用
public 公有的 在所有包下均可使用(前提是要import導包)
private 私有的 僅在本類中可以使用,任何其他類都不能使用
protected 受保護的 在本包下可以使用,也可以在被繼承的子類中使用,其他包下不能使用
  • static靜態的

static可以用於修飾成員變數、成員方法、程式碼塊。
使用static修飾符修飾類的成員變數和成員方法時,使他們均為靜態成員,也叫做類成員
被static所修飾的成員變數針對類而言,只有一份且被類的所有物件共同使用(訪問許可權夠的話),在類載入初期進行初始化一次,可以用類的例項來引用,建議直接用<類名稱>.<成員變數>對靜態成員變數訪問、賦值。
被static所修飾的成員方法也針對類而言,靜態成員方法中只能呼叫靜態的成員而不能呼叫非靜態的成員變數和成員方法,非靜態成員方法中可以引用靜態的成員變數和成員方法。其本質是兩者產生時間不一致,類載入初期在類的位元組碼檔案進入方法區時,靜態方法被執行,此時還未使用new構造方法來產生例項。所以靜態方法中也不能使用關鍵字this和super。即不能在靜態方法中引用非靜態的成員變數和成員方法。引用靜態成員方法的方式和引用靜態成員變數的方式類似。可以用例項來引用成員方法,建議直接用<類名稱>.<成員方法名>();來呼叫成員方法。
被static所修飾的程式碼塊稱為靜態程式碼塊,他們在程式中較為優先的執行。且每一個靜態程式碼塊僅執行一次,多個靜態程式碼塊根據書寫順序依次執行。

  • final最終的

final可用於修飾類、成員變數、成員方法。
被final所修飾的類不能能被繼承。因為繼承中可以存在方法的覆蓋(方法重寫),而final意為最終的,不可被修改。
被final修飾的成員變數的值可被稱為“只讀空間”,變數實際上就是空間,被final修飾的成員變數不能再被修改,也就是說只能且必須在定義時對用final修飾的成員變數進行初始化。被final修飾的成員變數意為“常量”,規定在定義常量時使用全大寫的字母對只讀空間命名。
被final修飾的成員方法不能被重寫。假如父類中存在被final所修飾的成員方法,在它的子類中不能覆蓋父類中的該方法。否則編譯出錯。

  • 類的例項化

在Java程式中,類不能直接使用其中的成員變數和成員方法(除非那些用public static final修飾工具類)而需要由物件為引用。以類為單位來建立物件、銷燬(由JVM自動完成而不需要程式設計師考慮)。建立一個物件就是構造一個類的例項。

  • 構造方法
	public <類名稱>() {
	}

構造方法名稱必須和類名稱完全一致(包括大小寫),構造方法不寫返回值(不是沒有返回值)。當不寫構造方法時,類中預設有一個無參構造方法。當寫了一個有參構造方法且未寫無參構造時,該無參構造消失,假如測試類中使用無參構造時會發生錯誤,若要使用該無參構造,則需在類中新增無參構造。每個構造方法第一句均預設為super();呼叫其父類構造方法。假如父類寫了有參構造未寫無參構造,則必須在子類所有構造方法中第一條寫super(<引數>);來先執行父類中有引數的構造方法,否則報錯。
一般類的構造方法用public修飾,但一些工具類為了保護方法本身,而用給出private修飾的構造方法,使用者不能在外界定義該物件。但可直接使用工具類給出的方法。
一般情況下,初始化一個物件是new 呼叫這個類中的一個構造方法。構造方法功能:常見一個類的物件時,用關鍵字new在堆空間中產生一個例項的空間,先進行預設初始化(類型別置null、整數型別置0、浮點型別置0.0、boolean型別置false),在進行構造初始化,最後根據情況執行賦值操作,再將該堆空間的首地址返回給棧空間中的物件(意為棧空間中物件指標指向堆空間)。

類的方法

  • 方法的定義
	<訪問許可權修飾符> <狀態修飾符> <返回值型別>(<>) {
		<方法體>;
		return <返回值型別是基本資料型別時返回的常量或者變數或者返回值型別是類型別時返回該類物件(被覆蓋其類中所有抽象方法的物件)>;
	}

Java中方法代表一種邏輯功能。類中的方法不能直接呼叫(除非是靜態方法,實際上靜態方法屬於類,不建議直接呼叫)。必須例項化類之後,用類的物件來引用類中的方法(靜態方法屬於類本身,用類名.呼叫類的靜態方法)。

  • 方法的傳參方式

Java規定,方法中的所有型別的引數傳遞都是“值傳遞”。當方法被呼叫執行時,首先對引數列表從右到左依次計算實際引數的值,然後在執行棧中為該方法的所有形式引數分配空間,再為方法中定義的區域性變數分配空間,最後將所有實際引數計算出的傳遞給該方法相應的形參變數空間。方法呼叫開始執行方法體中的語句。方法體執行結束後該方法在自動被JVM執行棧撤銷該方法的所有資訊,因而該方法在執行棧中為形式引數和區域性變數分配的空間也就自動撤銷。(釋放空間、垃圾回收)

  • 遞迴

在一個方法中,假如該方法呼叫了方法本身,這種方式就稱為“遞迴”。
遞迴是為了將一個複雜問題層層轉換為一個簡單的問題。當某個方法呼叫了第二個方法時,第一次呼叫的方法沒有結束!也就是說等到第二個方法執行結束時,返回到第一個方法中。這樣每呼叫一個方法,就有其他方法在棧記憶體中,沒有彈棧,棧記憶體沒有釋放,而越呼叫佔用越多,遞迴深度過大時,會導致棧溢位。即當所有被呼叫的方法都返回時,遞迴呼叫才能結束。所以遞迴要有結束條件,否則會引起無限遞迴而導致棧溢位。

  • 階乘
    基本思想:除了1,其他數的階乘等於該數本身乘以其值減一的階乘。
    注意此程式中使用int作為資料型別,所以階乘的值不能超過int所能表示的最大範圍。
public class Factorial {// 階乘
    public static int factorial(int num) {
        if (num < 1) {
            return -1;
        }
        if (num == 1) {
            return num;
        }
        return num * factorial(num - 1);
    }
    public static void main(String[] args) {
        int num = 6;
        System.out.println(num + "的階乘是" + factorial(num));
    }
}
  • 斐波那契數列
    基本思想是:除了第一個數和第二個數外,其他數都等於他們前面兩者數之和。
public class FibonacciSequence {//斐波那契數列
    public static int fib(int num) {
        if (num < 1) {
            return -1;
        }
        if (num == 1 || num == 2) {
            return 1;
        }
        return fib(num - 2) + fib(num - 1);
    }
    public static void main(String[] args) {
        for (int i = 1; i < 10; i++) {
            System.out.printf(fib(i) + "\t");
        }
    }
}
  • 漢諾塔
public class Hanoi {
    public static void hanoi(int n, char s, char a, char t) {
        if (n == 0) {
            return;
        }
        hanoi(n - 1, s, t, a);
        System.out.println(s + " -> " + t);
        hanoi(n - 1, a, s, t);
    }
    public static void main(String[] args) {
        hanoi(3, 's', 'a', 't');
    }
}

中序遍歷二叉樹(來實現遞迴)這裡以3層漢諾塔為例。
中序遍歷二叉樹
這裡遞迴的思想是將把n層漢諾塔的移動分為三步,首先把源柱子上的n - 1層塔以目標柱子為輔助移動到以輔助為目標的柱子上(hanoi(n - 1, s, t, a);),然後將源柱子上的一個漢諾塔移動到目標柱子上(System.out.println(s + " -> " + t);),最後將輔助柱子上的n-1層漢諾塔以源為輔助移動到以目標柱子為目標的柱子上(hanoi(n - 1, a, s, t);)。