Java基礎(chǔ)筆記(一) 面向?qū)ο?/h2>

Java基礎(chǔ)筆記(一) 面向?qū)ο?/h1>

[TOC]

1、定義類

[修飾符] class 類名
{
    零到多個(gè)構(gòu)造器定義
    零到多個(gè)Field
    零到多個(gè)方法
}

其中的修飾符可以是public、final、abstract或省略。


  1. 類也是引用數(shù)據(jù)類型,用類定義的變量也只是一個(gè)引用(或者說指針),里面只是存放了一個(gè)地址值。
  2. static修飾的方法不能直接訪問沒有static修飾的成員。(理由很簡單:靜態(tài)成員是獨(dú)立于具體對(duì)象而存在,屬于類本身,而非靜態(tài)成員是依賴于具體的對(duì)象的)
  3. Java里方法的參數(shù)傳遞方式只有一種:值傳遞?;緮?shù)據(jù)類型和引用數(shù)據(jù)類型都是將實(shí)參的一個(gè)副本傳給形參,只不過引用數(shù)據(jù)類型拷貝的是地址值!

2、可變參數(shù)函數(shù)

JDK 1.5之后,Java允許為方法指定數(shù)量不確定的形參,通過在最后一個(gè)形參的類型后增加三個(gè)點(diǎn)(…),代碼實(shí)例如下:

public class MyClass {
    /**
     * 可變參數(shù)的方法
     */
    public static void func(int a, String... str) {
        for(String s : str) {
            System.out.println(s);
        }
        System.out.println(a);
    }
    
    /**
     * 程序入口-main
     */
    public static void main(String[] args) {
        func(15, "第一個(gè)字符串","第二個(gè)字符串","第三個(gè)字符串");
    }
}

當(dāng)然,如果你覺得這樣麻煩,可以直接用一個(gè)數(shù)組代替


3、方法重載

Java允許同一個(gè)類里定義多個(gè)同名方法,只要形參列表不同就行。


在Java中,根據(jù)變量定義位置的不同,可以將變量分為兩大類:成員變量 和 局部變量

img

1、成員變量的初始化和內(nèi)存中的運(yùn)行機(jī)制

  • 當(dāng)系統(tǒng)加載類、或者創(chuàng)建該類的實(shí)例時(shí),系統(tǒng)自動(dòng)為成員變量分配內(nèi)存空間,并自動(dòng)指定初始值。
  • 類 Field(靜態(tài)成員變量),系統(tǒng)會(huì)在類加載時(shí)為其分配內(nèi)存空間,并指定默認(rèn)初始值。
  • 實(shí)例 Field 是在創(chuàng)建實(shí)例時(shí)分配內(nèi)存空間并指定初始值的,注意:實(shí)例變量指向的是這部分內(nèi)存。

2、局部變量的初始化和內(nèi)存中的運(yùn)行機(jī)制

  • 局部變量定義后,必須經(jīng)過顯式初始化后才能使用,系統(tǒng)不會(huì)為局部變量執(zhí)行初始化。
  • 也就是說,定義局部變量后,系統(tǒng)并未為這個(gè)變量分配內(nèi)存空間,直到等到程序?yàn)檫@個(gè)變量賦初值時(shí)才分配,并將初值保存在這塊內(nèi)存中。
  • 局部變量總是保存在其所在方法的棧內(nèi)存中,所以它不屬于任何類或?qū)嵗?/li>
  • 如果是基本類型的局部變量,則棧內(nèi)存中是變量的值;如果是引用類型的局部變量,則棧內(nèi)存中存放的是地址,引用堆內(nèi)存中的實(shí)際對(duì)象。

4、類的封裝

封裝是面向?qū)ο蟮娜筇卣髦?。為了?shí)現(xiàn)良好的封裝,需要:

  • 將 Field 和實(shí)現(xiàn)細(xì)節(jié)隱藏起來,不允許外部直接訪問。
  • 把方法作為外部接口暴露出來,讓方法來控制對(duì) Field 進(jìn)行安全的訪問和操作。

Java中提供了4個(gè)訪問控制級(jí)別:private、protected、public和不加任何訪問控制符(default),它們的訪問控制級(jí)別由小到大:

img

img


package、import 和 import static

包(package):為了解決類的命名沖突,Java引入了包機(jī)制,提供了類的多層命名空間。

如果一個(gè)類被放于某個(gè)包中,則我們應(yīng)該在該Java源文件的第一個(gè)非注釋行添加如下代碼:

package packageName;

import語句可以導(dǎo)入指定包下某個(gè)類或全部類,但import語句并不是必需的,只要堅(jiān)持在類里面使用其他類的全名,則可以無須使用import語句。

注意:在JDK 1.5以后增加了一種靜態(tài)導(dǎo)入(import static)的語法,用于導(dǎo)入指定類的某個(gè)靜態(tài) Field、方法或該類全部的靜態(tài) Field、方法。

import static package.subpackage...className.fieldName;  // 導(dǎo)入某一靜態(tài)變量
import static package.subpackage...className.methodName; // 導(dǎo)入某一靜態(tài)方法
import static package.subpackage...className.*;  // 導(dǎo)入該類的所有靜態(tài)Field、方法

用一句話歸納importimport static的作用:使用import可以省略寫包名,而使用import static則可以連類名都省略。


4、Java的常用包

Java的核心類都放在java這個(gè)包及其子包下,Java擴(kuò)展的許多類都放在javax包及其子包下。下面幾個(gè)包是Java語言中的常用包:

  • java.lang:這個(gè)包下包含了Java語言的核心類,如 String、Math、System 和 Thread 類等,使用這個(gè)包下的類無須使用 import 語句導(dǎo)入,系統(tǒng)會(huì)自動(dòng)導(dǎo)入這個(gè)包下的所有類。
  • java.util:這個(gè)包下包含了Java的大量工具類/接口和集合框架類/接口,例如 Arrays、List 和 Set 等。
  • java.net:這個(gè)包下包含了一些Java網(wǎng)絡(luò)編程相關(guān)的類/接口。
  • java.io:這個(gè)包下包含了一些Java輸入/輸出編程相關(guān)的類/接口。
  • java.text:這個(gè)包下包含了一些Java格式化相關(guān)的類。
  • java.sql:這個(gè)包下包含了Java進(jìn)行 JDBC 數(shù)據(jù)庫編程的相關(guān)類/接口。
  • java.awt:這個(gè)包下包含了抽象窗口工具集(Abstract Window Toolkits)的相關(guān)類/接口,這些類主要用于構(gòu)建 GUI 程序。
  • java.swing:這個(gè)包下包含了 Swing 圖形用戶界面編程的相關(guān)類/接口,這些類可用于構(gòu)建平臺(tái)無關(guān)的 GUI 程序。

5、構(gòu)造器

構(gòu)造器也就是構(gòu)造函數(shù)!?。?/p>

Java類可以包含一個(gè)或一個(gè)以上的構(gòu)造器。一旦程序員提供了自定義的構(gòu)造器,系統(tǒng)就不再提供默認(rèn)的無參構(gòu)造器了。(所以如果為一個(gè)類編寫了有參數(shù)的構(gòu)造器,通常建議為該類也額外提供一個(gè)無參數(shù)的構(gòu)造器)


6、類的繼承

繼承是面向?qū)ο蟮娜筇卣髦?。Java的繼承具有單繼承的特點(diǎn),每個(gè)子類只有一個(gè)直接父類。

繼承的語法格式:

修飾符 class Derive extends Base
{
    // 類定義部分
}

Java使用extends作為繼承的關(guān)鍵字,extends在英文中是擴(kuò)展的意思。

重寫父類的方法要遵循“兩同兩小一大”的規(guī)則:

  • “兩同”:方法名相同,形參列表相同。
  • “兩小”:子類方法返回值類型應(yīng)比父類方法返回值類型更小或相等,子類方法聲明拋出的異常類應(yīng)比父類方法聲明拋出的異常類更小或相等。
  • “一大”:子類方法的訪問權(quán)限應(yīng)比父類方法的訪問權(quán)限更大或相等。

如果需要在子類方法中調(diào)用父類中被覆蓋的方法,若被覆蓋的是實(shí)例方法,使用super作為調(diào)用者;若被覆蓋的是類方法,使用父類類名作為調(diào)用者。


7、構(gòu)造器的執(zhí)行順序

子類不會(huì)獲得父類的構(gòu)造器,但子類構(gòu)造器里可以調(diào)用父類構(gòu)造器。有如下幾種情況:

  • 子類構(gòu)造器函數(shù)體的第一行使用super顯式調(diào)用父類構(gòu)造器。
  • 子類構(gòu)造器函數(shù)體的第一行使用this顯示調(diào)用本類中重載的構(gòu)造器,執(zhí)行本類中另一個(gè)構(gòu)造器時(shí)即會(huì)調(diào)用父類構(gòu)造器。
  • 子類構(gòu)造器函數(shù)體中既沒有super調(diào)用,也沒有this調(diào)用,系統(tǒng)將會(huì)在執(zhí)行子類構(gòu)造器之前,隱式調(diào)用父類無參數(shù)的構(gòu)造器。

不管上面哪種情況,當(dāng)調(diào)用子類構(gòu)造器來初始化子類對(duì)象時(shí),父類構(gòu)造器總會(huì)在子類構(gòu)造器之前執(zhí)行;不僅如此,執(zhí)行父類構(gòu)造器時(shí),系統(tǒng)會(huì)再次上溯執(zhí)行其父類構(gòu)造器……依此類推,創(chuàng)建任何Java對(duì)象,最先執(zhí)行的總是java.lang.Object類的構(gòu)造器。


8、多態(tài)

多態(tài)是面向?qū)ο蟮娜筇卣髦弧?/p>

Java引用變量有兩個(gè)類型:一個(gè)是編譯時(shí)類型,一個(gè)是運(yùn)行時(shí)類型編譯時(shí)類型由聲明該變量時(shí)的類型決定,運(yùn)行時(shí)類型由實(shí)際賦給該變量的對(duì)象決定。兩個(gè)類型不一致時(shí),就可能出現(xiàn)多態(tài)。

當(dāng)把一個(gè)子類對(duì)象直接賦給父類引用變量時(shí),這個(gè)引用變量的編譯時(shí)類型是 BaseClass,而運(yùn)行時(shí)類型是 SubClass,當(dāng)運(yùn)行時(shí)調(diào)用該引用變量的方法時(shí),其方法行為總是表現(xiàn)出子類方法的行為特征,而不是父類方法的行為特征。也就是說:相同類型的變量 調(diào)用同一個(gè)方法時(shí),呈現(xiàn)出多種不同的行為特征,這就是多態(tài)。

多態(tài)的兩個(gè)前提: 要有繼承(inheritance),要有方法重寫(override)。


9、instanceof 運(yùn)算符

instanceof是Java中的一個(gè)二元運(yùn)算符,它的作用是在運(yùn)行時(shí)判斷左邊對(duì)象是否是右邊類(或其子類)的實(shí)例。如果是,返回true,否則返回false

public class MyClass {

    public static void main(String[] args) {
        String str = "";   // str 是String類型引用變量
        Object obj = "";   // obj 的編譯時(shí)類型是 Object,但實(shí)際類型是 String 
        System.out.println("str 是 String 的實(shí)例:" + (str instanceof String)); // true
        System.out.println("str 是 Object 的實(shí)例:" + (str instanceof Object)); // true
        System.out.println("obj 是 String 的實(shí)例:" + (obj instanceof String)); // true
        System.out.println("obj 是 Object 的實(shí)例:" + (obj instanceof Object)); // true
        System.out.println("obj 是 Math 的實(shí)例:" + (obj instanceof Math)); // false
    }
}

需要注意:instanceof運(yùn)算符前面操作數(shù)的編譯時(shí)類型要么與后面的類相同,要么與后面的類具有父子繼承關(guān)系,否則會(huì)引起編譯錯(cuò)誤。

instanceof運(yùn)算符的常用之處:在進(jìn)行強(qiáng)制類型轉(zhuǎn)換之前,首先判斷前一個(gè)對(duì)象是否是后一個(gè)類的實(shí)例,是否可以成功轉(zhuǎn)換,從而保證代碼更加健壯。


10、初始化塊

初始化塊是Java類里可出現(xiàn)的第4種成員(前面依次有 Field、方法和構(gòu)造器)。與構(gòu)造器的作用類似,初始化塊也可以對(duì)Java對(duì)象進(jìn)行初始化操作。

初始化塊的語法格式如下:

[修飾符] {
    // 可執(zhí)行代碼
    ...
}

初始化塊的修飾符只能是static,使用 static 修飾的初始化塊被稱為靜態(tài)初始化塊

一個(gè)類里可以有多個(gè)初始化塊,先定義的初始化塊先執(zhí)行,后定義的初始化塊后執(zhí)行,下面是一個(gè)例子:

public class MyClass {

    {
        int a = 5;
        System.out.println("第一個(gè)初始化塊!");
    }
    
    {
        System.out.println("第二個(gè)初始化塊!");
    }
    
    public MyClass() {
        System.out.println("類的無參數(shù)構(gòu)造器!");
    }
    
    public static void main(String[] args) {
        new MyClass();   // 創(chuàng)建一個(gè)對(duì)象
    }
}

控制臺(tái)輸出結(jié)果:

第一個(gè)初始化塊!
第二個(gè)初始化塊!
類的無參數(shù)構(gòu)造器!

可以看出,初始化塊是在構(gòu)造器之前執(zhí)行的。創(chuàng)建一個(gè) Java 對(duì)象時(shí),不僅會(huì)執(zhí)行該類的普通初始化塊和構(gòu)造器,而且系統(tǒng)會(huì)一直上溯到java.lang.Object類,先執(zhí)行 java.lang.Object 類的初始化塊,開始執(zhí)行 java.lang.Object 的構(gòu)造器,依次向下執(zhí)行其父類的初始化塊,開始執(zhí)行其父類的構(gòu)造器……最后才執(zhí)行該類的初始化塊和構(gòu)造器,返回該類的對(duì)象。

雖然 Java 允許一個(gè)類中定義多個(gè)的普通初始化塊,但這沒有任何意義,所以如果要使用初始化塊的話定義一個(gè)就行了。


11、初始化塊和構(gòu)造器的區(qū)別

初始化塊總是在構(gòu)造器之前執(zhí)行。雖然它們的作用非常相似,但依然存在一些差異的。

與構(gòu)造器不同的是,初始化塊是一段固定執(zhí)行的代碼,它不能接受任何參數(shù)。因此,如果有一段初始化的代碼對(duì)所有對(duì)象完全相同,且無須接收任何參數(shù),就可以把這段初始化代碼提取到初始化塊中。

img

通過把多個(gè)構(gòu)造器中的相同代碼提取到初始化塊中,能更好地提高初始化代碼的復(fù)用,提高整個(gè)應(yīng)用的可維護(hù)性。


12、靜態(tài)初始化塊

初始化塊的修飾符只能是static,使用 static 修飾的初始化塊被稱為靜態(tài)初始化塊

靜態(tài)初始化塊,也屬于類的靜態(tài)成員,因此靜態(tài)初始化塊不能訪問非靜態(tài)成員(包括實(shí)例Field和實(shí)例方法)。靜態(tài)初始化塊用于對(duì)整個(gè)類進(jìn)行初始化處理,通常用于對(duì)類Field執(zhí)行初始化處理。

系統(tǒng)將在類初始化階段執(zhí)行靜態(tài)初始化塊,而不是在創(chuàng)建對(duì)象時(shí)才執(zhí)行。因此,靜態(tài)初始化塊總是比普通初始化塊先執(zhí)行。與普通初始化塊類似的是,系統(tǒng)在類初始化階段不僅會(huì)執(zhí)行本類的靜態(tài)初始化塊,還會(huì)一直上溯到 java.lang.Object 類(如果它包含靜態(tài)初始化塊),從上往下依次執(zhí)行其父類的靜態(tài)初始化塊……最后才執(zhí)行該類的靜態(tài)初始化塊。經(jīng)過這個(gè)過程,才完成了該類的初始化。而只有類完成初始化以后,才可以在系統(tǒng)中使用這個(gè)類,包括訪問這個(gè)類的類Field、類方法,或者用這個(gè)類來創(chuàng)建實(shí)例。


13、包裝類

Java 是面向?qū)ο蟮木幊陶Z言,但它也包含了 8 種基本數(shù)據(jù)類型。基本數(shù)據(jù)類型的數(shù)據(jù)不具備“對(duì)象”的特性:沒有Field、方法可以被調(diào)用。

所有引用類型的變量都繼承了Object類,都可當(dāng)成 Object 類型變量使用,但基本數(shù)據(jù)類型的變量卻不可以。為了解決這個(gè)問題,Java 提供了包裝類(Wrapper Class),可以把 8 個(gè)基本類型的值包裝成對(duì)象使用。

img

把基本數(shù)據(jù)類型變量 包裝成 對(duì)應(yīng)的包裝類對(duì)象 是通過對(duì)應(yīng)包裝類的構(gòu)造器來實(shí)現(xiàn)的,不僅如此,8個(gè)包裝類中除了 Character 之外,還可以通過傳入一個(gè)字符串來構(gòu)建包裝類對(duì)象。

public class MyClass {

    public static void main(String[] args) {
        boolean b1 = true;
        int i1 = 5;
        
        Boolean _b = new Boolean(b1);
        Integer _i = new Integer(i1);
        Float _f = new Float("3.14");
        
        // 取出包裝類對(duì)象里的值
        boolean b2 = _b.booleanValue();
        int i2 = _i.intValue();
        float f2 = _f.floatValue();
    }
}

可能你會(huì)覺得,這樣的轉(zhuǎn)換有些繁瑣。但從 JDK 1.5 開始提供了自動(dòng)裝箱(Autoboxing)自動(dòng)拆箱(AutoUnboxing)功能,即可以把一個(gè)基本類型變量直接賦給對(duì)應(yīng)的包裝類變量或 Object 變量(自動(dòng)裝箱),也可以把包裝類對(duì)象直接賦給一個(gè)對(duì)應(yīng)的基本類型變量。


14、基本類型變量與字符串的轉(zhuǎn)換

img


15、toString( )方法

toString()方法是 Object 類里的一個(gè)實(shí)例方法,而所有的 Java 類都是 Object 類的子類,因此所有的 Java 對(duì)象都具有 toString() 方法。

不僅如此,所有的 Java 對(duì)象都可以和字符串進(jìn)行連接運(yùn)算,也可以使用System.out.println()進(jìn)行輸出。當(dāng)進(jìn)行上面的操作時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用 Java 對(duì)象的 toString()方法,使用其返回的字符串。

Object 類的toString方法是一個(gè)“自我描述”的方法,它總是返回該對(duì)象實(shí)現(xiàn)類的“類名@hashCode”值。但是這個(gè)返回值并不能真正實(shí)現(xiàn)“自我描述”的功能,這時(shí)可以對(duì)這個(gè)方法進(jìn)行重寫。


16、==和equals的區(qū)別

Java 程序中判斷兩個(gè)變量是否相等有兩種方式:一種是使用==運(yùn)算符,另一種是使用equals方法。

  • 對(duì)于基本類型變量來說,它們并沒有equals方法,只能使用==判斷兩個(gè)變量的值是否相等。
  • 對(duì)于引用類型變量來說,==運(yùn)算符是判斷兩個(gè)引用變量是否指向內(nèi)存中的同一個(gè)對(duì)象,也就是比較對(duì)象的內(nèi)存地址;而equals是比較兩個(gè)對(duì)象的值是否相等(String類,Integer類等等)。

需要知道的是,equals 方法是 Object 類的一個(gè)實(shí)例方法。在 Object 類中equals方法和==沒有任何區(qū)別,都是判斷兩個(gè)變量是否指向同一個(gè)對(duì)象。<u>而String類,Integer類等等一些類,是重寫了equals方法,才使得equals和“==”不同。</u>

所以,當(dāng)自己創(chuàng)建類時(shí),想要自定義相等的標(biāo)準(zhǔn),必須重寫equals方法。


17、final修飾符

Java 提供了final關(guān)鍵字來修飾變量、方法和類。系統(tǒng)不允許為 final變量重新賦值,子類不允許覆蓋父類的final方法,不允許繼承final類。

  • final 成員變量必須由程序員顯式地指定初始值,系統(tǒng)不會(huì)對(duì) final 成員變量進(jìn)行隱式初始化。對(duì)于 final 修飾的類 Field,必須在聲明該Field時(shí)或在靜態(tài)初始化塊中指定初始值;對(duì)于 final 修飾的實(shí)例 Field,必須在聲明該Field時(shí)、普通初始化塊或構(gòu)造器中指定初始值。
  • 前面說過,系統(tǒng)不會(huì)為局部變量執(zhí)行隱式初始化,必須由程序員顯式指定。對(duì)于 final 修飾的局部變量,可以在聲明時(shí)指定初始值,也可以在后面的代碼中對(duì)其賦值,但只能一次。
  • final 修飾基本類型變量時(shí),表示變量的值不能被改變;final 修飾引用類型變量時(shí),表示該變量所引用的地址不能被改變,即一直引用同一個(gè)對(duì)象,但這個(gè)對(duì)象是可以改變的。
  • 當(dāng)定義 final 變量時(shí)就為該變量指定了初始值,而且該初始值可以在編譯時(shí)就被確定下來,那么這個(gè)變量就變成了“宏變量”。編譯器會(huì)把程序中所有用到該變量的地方直接替換成該變量的值。

18、抽象類與抽象方法

Java 中使用abstract修飾符來定義抽象類和抽象方法。有抽象方法的類必須定義成抽象類,但抽象類里可以沒有抽象方法。

抽象類不能被實(shí)例化,只能當(dāng)作父類被其他子類繼承。抽象方法沒有函數(shù)體,必須由子類提供實(shí)現(xiàn)(即重寫)。

abstract不能同時(shí)使用的關(guān)鍵字:

  1. final和abstract不能同時(shí)使用,因?yàn)樗鼈兪菍?duì)立的。
  2. static和abstract不能同時(shí)修飾某個(gè)方法,因?yàn)槿绻粋€(gè)抽象方法被定義成靜態(tài)方法,通過類名調(diào)用該方法將出現(xiàn)錯(cuò)誤。
  3. private和abstract不能同時(shí)修飾某個(gè)方法,因?yàn)槌橄蠓椒ū仨毐蛔宇愔貙懖庞幸饬x,而子類不能訪問和重寫父類的 private 方法。

19、接口(interface)

上面說到,抽象類既可以包含抽象方法,也可以普通方法。而接口(interface)是一種更徹底的抽象,接口里的所有方法都是抽象方法。

接口定義的是多個(gè)類共同的公共行為規(guī)范,故它里面通常是定義一組公用方法?;菊Z法如下:

[修飾符] interface 接口名 extends 父接口1,父接口2...
{
    零個(gè)到多個(gè)常量定義...
    零個(gè)到多個(gè)抽象方法定義...
}

修飾符可以是 public 或者省略,如果省略了 public 訪問控制符,則默認(rèn)采用包權(quán)限訪問控制符。另外,與類繼承不同的是,接口繼承中一個(gè)接口可以有多個(gè)直接父接口(接口只能繼承接口而不能繼承類)。

由于接口是一種規(guī)范,因此接口里不能包含構(gòu)造器和初始化塊。接口里可以包含3種成員: Field(只能是常量)、方法(只能是抽象方法)、內(nèi)部類(包括內(nèi)部接口、枚舉)。

  • 接口里所有成員都是public訪問權(quán)限。
  • 接口里的常量 Field 是使用public static final修飾符來修飾,不管定義時(shí)是否指定。
  • 接口里的方法是自動(dòng)使用public abstract修飾符修飾,不管定義方法時(shí)是否指定。
  • 接口里的內(nèi)部類(接口、枚舉類)是自動(dòng)使用public static修飾符修飾,不管定義時(shí)是否指定。

接口不能用于創(chuàng)建實(shí)例,其主要用途是被實(shí)現(xiàn)類實(shí)現(xiàn)。實(shí)現(xiàn)使用implements關(guān)鍵字:

[修飾符] class 類名 extends 父類 implements 接口1,接口2...
{
    // 類體部分
}

一個(gè)類只能有一個(gè)直接父類,但一個(gè)類可以實(shí)現(xiàn)多個(gè)接口。實(shí)現(xiàn)接口與繼承父類相似,也可以獲得所實(shí)現(xiàn)的接口里定義的成員,因此可以把實(shí)現(xiàn)接口理解為一種特殊的繼承。


20、接口與抽象類的比較

相同點(diǎn):

  • 接口和抽象類都不能被實(shí)例化,它們都用于被其他類實(shí)現(xiàn)或繼承。
  • 接口和抽象類都可以包含抽象方法,實(shí)現(xiàn)接口或繼承抽象類的普通子類都必須實(shí)現(xiàn)這些抽象方法。

不同點(diǎn):

  • 接口里只能包含抽象方法,而抽象類既可以抽象方法也可以包含普通方法,還可以沒有抽象方法。
  • 接口里不能定義靜態(tài)方法(因?yàn)槿渴浅橄蠓椒ǎ橄箢惱锟梢远x靜態(tài)方法。
  • 接口里只能定義靜態(tài)常量 Field,而抽象類既可以定義普通 Field,也可以定義靜態(tài)常量 Field。
  • 接口里不包含構(gòu)造器和初始化塊,而抽象類里完全可以包含。
  • 一個(gè)類最多只能有一個(gè)直接父類,但卻可以直接實(shí)現(xiàn)多個(gè)接口(彌補(bǔ)Java單繼承的不足)。

21、內(nèi)部類

在Java類里只能包含5種成員:Field、方法、構(gòu)造器、初始化塊、內(nèi)部類(包括接口和枚舉類)。前四種類成員已經(jīng)介紹過了,下面介紹一下內(nèi)部類。

內(nèi)部類也叫嵌套類,語法格式:

public class OuterClass
{
    // 此處可以定義內(nèi)部類
}

通常,我們把內(nèi)部類作為成員內(nèi)部類來定義,而不是作為局部內(nèi)部類(在方法里定義的內(nèi)部類)。

img

非靜態(tài)內(nèi)部類里不允許定義靜態(tài)成員,而靜態(tài)內(nèi)部類里可以定義靜態(tài)成員,也可以定義非靜態(tài)成員。

根據(jù)靜態(tài)成員不能訪問非靜態(tài)成員的規(guī)則,外部類的靜態(tài)方法不能使用非靜態(tài)內(nèi)部類,靜態(tài)內(nèi)部類也不能訪問外部類的非static成員。


22、枚舉類

枚舉類是一種不能自由創(chuàng)建對(duì)象的類,它的對(duì)象在定義類時(shí)已經(jīng)固定下來。枚舉類特別適合定義像行星、季節(jié)這樣的類,它們能創(chuàng)建的實(shí)例是有限且確定的。

在 Java 1.5 以前,要定義一個(gè)枚舉類,必須手動(dòng)去實(shí)現(xiàn)。下面就是一個(gè) Season 枚舉類的例子:

public class Season {
    
    private final String name;
    private final String description;
    
    public static final Season SPRING = new Season("春天","春暖花開");
    public static final Season SUMMER = new Season("夏天","夏日炎炎");
    public static final Season FALL = new Season("秋天","秋高氣爽");
    public static final Season WINTER = new Season("冬天","圍爐賞雪");
    
    // 私有化構(gòu)造器
    private Season(String name, String description) {
        this.name = name;
        this.description = description;
    }
    
    // 只為兩個(gè) Field 提供 getter 方法
    public String getName() {
        return name;
    }
    public String getDescription() {
        return description;
    }
}

上面的 Season 類是一個(gè)不可變類,它只能創(chuàng)建4種對(duì)象,可以通過Season.SPRING的方式來取得 Season 對(duì)象。

Java 1.5 新增了一個(gè)enum關(guān)鍵字,用以定義枚舉類:

public enum Season {
    SPRING,SUMMER,FALL,WINTER;
}

枚舉類(enum)是一種特殊的類,它一樣可以有自己的 Field、方法和構(gòu)造器,可以實(shí)現(xiàn)一個(gè)或者多個(gè)接口。因?yàn)樗厥?,所以有幾點(diǎn)需要注意:

  1. enum定義的枚舉類默認(rèn)繼承了java.lang.Enum類,而不是繼承 Object 類。
  2. enum定義的非抽象的枚舉類默認(rèn)使用 final 修飾,因此枚舉類不能派生子類。
  3. 枚舉類的構(gòu)造器默認(rèn)使用且只能使用private訪問控制符修飾。
  4. 枚舉類的所有實(shí)例必須在枚舉類的第一行顯式列出,并且系統(tǒng)會(huì)自動(dòng)添加public static final修飾。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容