一、簡介
描述:
- 很多時(shí)候我們創(chuàng)建類的對象的時(shí)候并不需要使用很多次,每次只使用一次,這個(gè)時(shí)候我們就可以使用內(nèi)部類了。
- 內(nèi)部類不是在一個(gè)java源文件中編寫兩個(gè)平行的類,而是在一個(gè)類的內(nèi)部再定義另外一個(gè)類。 我們可以把外邊的類稱為外部類,在其內(nèi)部編寫的類稱為內(nèi)部類。
分類:
- 成員內(nèi)部類
- 靜態(tài)內(nèi)部類
- 局部內(nèi)部類
- 匿名內(nèi)部類
內(nèi)部類通用用法:
- 要想訪問內(nèi)部類中的內(nèi)容,必須通過外部類或外部類對象。
- 內(nèi)部類可以訪問外部類的所有訪問權(quán)限的屬性和方法,包括私有的成員變量、方法。原理就是在通過外部類對象實(shí)例化內(nèi)部類對象時(shí),外部類對象把自己的引用傳進(jìn)了內(nèi)部類,使內(nèi)部類可以用通過'外部類名.this'去調(diào)用外部類的屬性和方法。一般都是隱式調(diào)用了,但是當(dāng)內(nèi)部類中有屬性或者方法名和外部類中的屬性或方法名相同的時(shí)候,就需要通過顯式調(diào)用'外部類名.this.外部類屬性名'了。
二、成員內(nèi)部類
描述:
- 成員內(nèi)部類又叫實(shí)例內(nèi)部類、非靜態(tài)內(nèi)部類。
- 一個(gè)類在另一個(gè)類的內(nèi)部,那么想要使用這個(gè)內(nèi)部類,就必須先要有外部類的一個(gè)實(shí)例對象,然后在通過該對象去使用內(nèi)部類。
注意:
- 成員內(nèi)部類中可以訪問外部類的所有屬性和方法,包括私有的成員變量、方法。
- 成員內(nèi)部類中不能寫靜態(tài)的屬性和方法。
- 實(shí)例化內(nèi)部類,首先需要實(shí)例化外部類,通過外部類去調(diào)用內(nèi)部類。
- 如果內(nèi)部類中的變量名和外部類的成員變量名一樣,在內(nèi)部類中,要通過'外部類名.this.外部類屬性名'來訪問外部類屬性,通過'this.內(nèi)部類屬性名'來訪問內(nèi)部類屬性。
示例:
class Outer {
private int id;
private String name = "outer";
public void out() {
System.out.println("這是外部類方法");
}
class Inner {
private int id = 8;
public void in() {
System.out.println("這是內(nèi)部類方法");
}
public void test() {
System.out.print(name + " " + Outer.this.id + " " + id);
}
}
}
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.test();//outer 0 8
}
}
三、靜態(tài)內(nèi)部類
描述:
- 使用'static'修飾的內(nèi)部類就叫靜態(tài)內(nèi)部類。
- 靜態(tài)內(nèi)部類是外部類的靜態(tài)成員,從屬于外部類,不從屬于外部類對象。
特點(diǎn):
- 靜態(tài)內(nèi)部類能夠直接被外部類給實(shí)例化,不需要使用外部類對象。
- 靜態(tài)內(nèi)部類中可以聲明靜態(tài)方法和靜態(tài)變量。
- 靜態(tài)內(nèi)部類中沒有外部類對象的引用,所以不能使用外部類的非靜態(tài)屬性和方法。
示例:
public class Test {
private String name;
private static int age;
public void run() {
}
public static void go() {
}
private static class StaticInnerClass {
private String name;
private static int age;
public void test1(String name) {
System.out.println(name + " " + this.name + " " + StaticInnerClass.age + " " + Test.age);
/*
靜態(tài)內(nèi)部類不能訪問外部類非靜態(tài)屬性
System.out.println(Test.this.name);
*/
Test.go();
/*
靜態(tài)類不能訪問非靜態(tài)方法
Test.this.run();
*/
}
public static void test2(String name) {
/* 內(nèi)部類的靜態(tài)方法只能訪問自己和外部類的靜態(tài)屬性和方法 */
System.out.print(name + " " + StaticInnerClass.age + " " + Test.age);
/*
內(nèi)部類的靜態(tài)方法不能訪問外部類的非靜態(tài)屬性
System.out.println(Test.this.name);
*/
/*
內(nèi)部類的靜態(tài)方法里面連自己類的非靜態(tài)屬性都不能訪問
System.out.println(this.name);
*/
Test.go();
/*
內(nèi)部類的靜態(tài)方法不能訪問非靜態(tài)方法
Test.this.run();
*/
}
}
/* 外部類訪問靜態(tài)內(nèi)部類 */
public static void main(String[] args) {
/* 靜態(tài)的內(nèi)部類不需要依賴外部類,所以不用new外部類對象 */
StaticInnerClass sic = new StaticInnerClass();
/* 內(nèi)部類對象調(diào)用內(nèi)部類成員變量和成員方法 */
sic.name = "張三";
sic.test1("李四");//李四 張三 0 0
/* 內(nèi)部類調(diào)用內(nèi)部類靜態(tài)變量和靜態(tài)方法 */
StaticInnerClass.age = 10;
StaticInnerClass.test2("王五");//王五 10 0
}
}
四、局部內(nèi)部類
描述:
- 局部內(nèi)部類是在方法內(nèi)部聲明的類。
- 局部內(nèi)部類只能在所在的方法中使用,生命周期相當(dāng)于一個(gè)局部變量,只能在方法體里。
- 局部內(nèi)部類的作用跟在成員內(nèi)部類差不多,也可以訪問所在外部類的成員變量及方法。
注意:
- 局部內(nèi)部類不能通過外部類對象直接實(shí)例化,而是在方法中實(shí)例化出自己來,然后通過內(nèi)部類對象調(diào)用自己類中的方法。
- 局部內(nèi)部類中如果要訪問該內(nèi)部類所在方法中的局部變量,那么這個(gè)局部變量就必須是'final'修飾的。'final'修飾的變量會(huì)變?yōu)槌A?,在常量池中放著。如果不變?yōu)槌A?,?dāng)局部內(nèi)部類被實(shí)例化后,方法彈棧,局部變量隨著跟著消失,這個(gè)時(shí)候局部內(nèi)部類對象想去調(diào)用該局部變量,就會(huì)出錯(cuò),因?yàn)樵摼植孔兞恳呀?jīng)沒了。當(dāng)局部變量變?yōu)槌A亢?,就?huì)將其加入常量池中,即使方法彈棧了,該局部變量還在常量池中呆著,局部內(nèi)部類也就是夠調(diào)用。所以局部內(nèi)部類想要調(diào)用局部變量時(shí),需要使用'final'修飾,不使用,編譯都通不過。
示例:
public class Test {
private String name;
private static int age;
public void run() {
}
public static void go() {
}
public void test() {
final String myName = "王五";
/* 局部內(nèi)部類要定義在方法中 */
class LocalInnerClass {
private String name;
/*
不能定義靜態(tài)屬性
private static int age;
*/
public void test(String name) {
System.out.println(name + " " + this.name + " " + myName + " " + Test.this.name);
Test.this.run();
Test.go();
}
}
LocalInnerClass lic = new LocalInnerClass();
lic.name = "張三";
lic.test("李四");//李四 張三 王五 null
}
public static void main(String[] args) {
new Test().test();
}
}
五、匿名內(nèi)部類
描述:
- 匿名內(nèi)部類是最常用的一種內(nèi)部類。
- 匿名內(nèi)部類是只會(huì)使用一次的類。那么就不需要先定義一個(gè)類,而是等到需要用的時(shí)候,再臨時(shí)實(shí)現(xiàn)并使用這個(gè)類。
- 匿名內(nèi)部類需要依托于其他類或者接口來創(chuàng)建。如果依托的是類,那么創(chuàng)建出來的匿名內(nèi)部類就默認(rèn)是這個(gè)類的子類;如果依托的是接口,那么創(chuàng)建出來的匿名內(nèi)部類就默認(rèn)是這個(gè)接口的實(shí)現(xiàn)類。
- 匿名內(nèi)部類的聲明必須是在使用'new'關(guān)鍵字的時(shí)候。匿名內(nèi)部類的聲明及創(chuàng)建對象必須一氣呵成,并且之后不能反復(fù)使用,因?yàn)闆]有名字。
注意:
- 匿名內(nèi)部類除了依托的類或接口之外,不能指定繼承或者實(shí)現(xiàn)其他類或接口,同時(shí)也不能被其他類所繼承,因?yàn)闆]有名字。
- 匿名內(nèi)部類中,我們不能寫出其構(gòu)造器,因?yàn)闆]有名字。
- 匿名內(nèi)部類中,除了重寫或?qū)崿F(xiàn)依托的類或接口的方法外,一般不會(huì)再寫其他獨(dú)有的方法,因?yàn)閺耐獠坎荒苤苯诱{(diào)用到(間接是調(diào)用到的)。
語法:
new Class(){
/* 重寫類里的方法,或者實(shí)現(xiàn)類或接口中的抽象方法。 */
}
示例:
interface Person {
public void say();
}
public class Test {
public static void main(String[] args) {
/*
new Class(){}的作用就是將接口給實(shí)現(xiàn)了,只不過這里實(shí)現(xiàn)該接口的是一個(gè)匿名類,也就是說這個(gè)類沒名字,只能使用這一次。
我們知道了這是一個(gè)類,將其new出來,就能獲得一個(gè)實(shí)現(xiàn)了Person接口的類的實(shí)例對象,通過該實(shí)例對象,就能調(diào)用該類中的方法了。
因?yàn)樵撃涿愂窃谝粋€(gè)類中實(shí)現(xiàn)的,所以叫其匿名內(nèi)部類。
*/
new Person() {
public void say() {
System.out.println("實(shí)現(xiàn)了Person接口的方法");
}
}.say();//實(shí)現(xiàn)了Person接口的方法
}
}
|