Java基礎(chǔ)筆記(一) 面向?qū)ο?/h1>
[TOC]
1、定義類
[修飾符] class 類名
{
零到多個(gè)構(gòu)造器定義
零到多個(gè)Field
零到多個(gè)方法
}
其中的修飾符可以是public、final、abstract或省略。
- 類也是引用數(shù)據(jù)類型,用類定義的變量也只是一個(gè)引用(或者說指針),里面只是存放了一個(gè)地址值。
-
static修飾的方法不能直接訪問沒有static修飾的成員。(理由很簡單:靜態(tài)成員是獨(dú)立于具體對(duì)象而存在,屬于類本身,而非靜態(tài)成員是依賴于具體的對(duì)象的) - 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ù)變量定義位置的不同,可以將變量分為兩大類:成員變量 和 局部變量
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í)別由小到大:
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、方法
用一句話歸納import和import 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ù),就可以把這段初始化代碼提取到初始化塊中。
通過把多個(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ì)象使用。
把基本數(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)換
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)鍵字:
- final和abstract不能同時(shí)使用,因?yàn)樗鼈兪菍?duì)立的。
- static和abstract不能同時(shí)修飾某個(gè)方法,因?yàn)槿绻粋€(gè)抽象方法被定義成靜態(tài)方法,通過類名調(diào)用該方法將出現(xiàn)錯(cuò)誤。
- 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)部類)。
非靜態(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)需要注意:
- 用
enum定義的枚舉類默認(rèn)繼承了java.lang.Enum類,而不是繼承 Object 類。 - 用
enum定義的非抽象的枚舉類默認(rèn)使用 final 修飾,因此枚舉類不能派生子類。 - 枚舉類的構(gòu)造器默認(rèn)使用且只能使用
private訪問控制符修飾。 - 枚舉類的所有實(shí)例必須在枚舉類的第一行顯式列出,并且系統(tǒng)會(huì)自動(dòng)添加
public static final修飾。