Java中的內(nèi)部類
- 什么是內(nèi)部類
內(nèi)部類是指在一個(gè)外部類的內(nèi)部再定義一個(gè)類。內(nèi)部類可以是靜態(tài)static的,也可用public,default,protected和private修飾。(而外部頂級(jí)類即類名和文件名相同的只能使用public和default)。注意:內(nèi)部類是一個(gè)編譯時(shí)的概念,一旦編譯成功,就會(huì)成為完全不同的兩類。對(duì)于一個(gè)名為Outer的外部類和其內(nèi)部定義的名為Inner的內(nèi)部類。編譯完成后出現(xiàn)Outer.class和Outer$Inner.class兩類。所以內(nèi)部類的成員變量/方法名可以和外部類的相同。java內(nèi)部類分為: 成員內(nèi)部類、靜態(tài)嵌套類、局部內(nèi)部類、匿名內(nèi)部類 。
- 內(nèi)部類的共性
(1)、內(nèi)部類仍然是一個(gè)獨(dú)立的類,在編譯之后內(nèi)部類會(huì)被編譯成獨(dú)立的.class文件,但是前面冠以外部類的類名和$符號(hào) 。(2)、內(nèi)部類不能用普通的方式訪問。內(nèi)部類是外部類的一個(gè)成員,因此內(nèi)部類可以自由地訪問外部類的成員變量,無論是否是private的 。(3)、內(nèi)部類聲明成靜態(tài)的,就不能隨便的訪問外部類的成員變量了,此時(shí)內(nèi)部類只能訪問外部類的靜態(tài)成員變量 。 - 成員內(nèi)部類
public class Outer {
private int a = 10;
private int b = 15;
public void print() {
System.out.println("Outer.a="+this.a);
}
public int add(int i,int j) {
return i+j;
}
class Inner {
private int a = 20;
private int c = b;
public void print() {
//內(nèi)部類訪問外部類中的同名成員變量
System.out.println("Outer.a="+Outer.this.a);
System.out.println("Inner.a="+this.a);
System.out.println("a="+a);
//內(nèi)部類中可以直接訪問外部類的成員變量和方法(內(nèi)部類對(duì)象持有指向外部類對(duì)象的引用。)
System.out.println("c="+c);
System.out.println("c+1="+add(c,1));
}
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.print();
//內(nèi)部類對(duì)象的創(chuàng)建依賴于外部類對(duì)象;
outer.new Inner().print();
}
}這個(gè)類編譯后出現(xiàn)Outer.class和Outer$Inner.class兩個(gè)class文件。編譯后成為兩個(gè)獨(dú)立的類,
因此,內(nèi)部類中可以定義與外部類中同名的屬性和方法。
成員內(nèi)部類,就是作為外部類的成員,與外部類的屬性、方法并列。可以直接使用外部類的所有成員和方法,即使是private的。
同時(shí)外部類要訪問內(nèi)部類的所有成員變量和方法,則需要通過內(nèi)部類的對(duì)象來獲取。要注意的是,成員內(nèi)部類不能含有static的變量和方法。因?yàn)槌蓡T內(nèi)部類需要先創(chuàng)建了外部類,才能創(chuàng)建它自己的
- 局部內(nèi)部類
局部內(nèi)部類,是指內(nèi)部類定義在方法和作用域內(nèi)。(1)、定義在方法內(nèi)
public class Teacher {
private String name;
private int age;
public void teach() {
final String str = "I'm a teacher!";
class EnglishTeacher {
public void teachEnglish() {
System.out.println("My name is "+name);
System.out.println("I'm "+age);
System.out.println(str);
System.out.println("I teach English");
}
}
EnglishTeacher englishTeacher = new EnglishTeacher();
englishTeacher.teachEnglish();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Teacher teacher = new Teacher();
teacher.name = "張三";
teacher.age = 35;
teacher.teach();
}
}
(2)、定義在作用域內(nèi)
public class Teacher1 {
private String name;
private int age;
public void teach(String course) {
final String str = "I'm a teacher!";
System.out.println(str);
if("English".equals(course)) {
class EnglishTeacher {
public void teachEnglish() {
System.out.println("My name is "+name);
System.out.println("I'm "+age);
System.out.println("I teach English");
}
}
EnglishTeacher englishTeacher = new EnglishTeacher();
englishTeacher.teachEnglish();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Teacher1 teacher = new Teacher1();
teacher.name = "張三";
teacher.age = 35;
teacher.teach("English");
}
}
(1)、局部內(nèi)部類只能在定義該內(nèi)部類的方法內(nèi)實(shí)例化,不可以在此方法外對(duì)其實(shí)例化。(2)、局部內(nèi)部類對(duì)象不能使用該內(nèi)部類所在方法的非final局部變量。
(3)、局部內(nèi)部類的地位和方法內(nèi)的局部變量的位置類似,因此不能修飾局部變量的修飾符也不能修飾局部內(nèi)部類,
譬如public、private、protected、static、transient等因?yàn)榉椒ǖ木植孔兞课挥跅I希淮嬖谟谠摲椒ǖ纳趦?nèi)。當(dāng)一個(gè)方法結(jié)束,其棧結(jié)構(gòu)被刪除,局部變量成為歷史。但是該方法結(jié)束之后,在方法內(nèi)創(chuàng)建的內(nèi)部類對(duì)象可能仍然存在于堆中!例如,如果對(duì)它的引用被傳遞到其他某些代碼,并存儲(chǔ)在一個(gè)成員變量內(nèi)。正因?yàn)椴荒鼙WC局部變量的存活期和方法內(nèi)部類對(duì)象的一樣長,所以內(nèi)部類對(duì)象不能使用它們。 - 靜態(tài)嵌套類
public class StaticOuter {
private int a = 10;
private static int b = 15;
static class StaticInner {
public static void print() {
System.out.println("b="+b);
}
void print1() {
System.out.println("b="+b);
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
StaticOuter.StaticInner.print();
new StaticOuter.StaticInner().print1();
}
}
嵌套類和普通的內(nèi)部類還有一個(gè)區(qū)別:普通內(nèi)部類不能有static數(shù)據(jù)和static屬性,也不能包含嵌套類,但嵌套類可以。
而嵌套類不能聲明為private,一般聲明為public,方便調(diào)用。
在靜態(tài)方法中定義的內(nèi)部類也是StaticNested Class,這時(shí)候不能在類前面加static關(guān)鍵字,靜態(tài)方法中的StaticNested Class與
普通方法中的內(nèi)部類的應(yīng)用方式很相似,它除了可以直接訪問外部類中的static的成員變量,還可以訪問靜態(tài)方法中的局部變量,
但是,該局部變量前必須加final修飾符。
- 匿名內(nèi)部類
- 為什么需要內(nèi)部類
匿名內(nèi)部類就是沒有名字的內(nèi)部類。什么情況下需要使用匿名內(nèi)部類?如果滿足下面的一些條件,使用匿名內(nèi)部類是比較合適的:
·只用到類的一個(gè)實(shí)例 。
·類在定義后馬上用到。
·類非常小(SUN推薦是在4行代碼以下)
·給類命名并不會(huì)導(dǎo)致你的代碼更容易被理解。
在使用匿名內(nèi)部類時(shí),要記住以下幾個(gè)原則:
·匿名內(nèi)部類不能有構(gòu)造方法。
·匿名內(nèi)部類不能定義任何靜態(tài)成員、靜態(tài)方法。
·匿名內(nèi)部類不能是public,protected,private,static。
·只能創(chuàng)建匿名內(nèi)部類的一個(gè)實(shí)例。
·一個(gè)匿名內(nèi)部類一定是在new的后面,用其隱含實(shí)現(xiàn)一個(gè)接口或?qū)崿F(xiàn)一個(gè)類。
·因匿名內(nèi)部類為局部內(nèi)部類,所以局部內(nèi)部類的所有限制都對(duì)其生效。(1)、繼承式的匿名內(nèi)部類
public class Singer {
public void sing() {
System.out.println("Sing a song");
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Singer singer = new Singer() {
@Override
public void sing() {
// TODO Auto-generated method stub
System.out.println("Sing a popular song");
}
};
singer.sing();
}
}
輸出結(jié)果:Sing a popular song
(2)、接口式的匿名內(nèi)部類
public interface Programmer {
public void code();
}
public class TestProgrammer {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Programmer javaProgrammer = new Programmer() {
@Override
public void code() {
// TODO Auto-generated method stub
System.out.println("Java programmer");
}
};
javaProgrammer.code();
Programmer phpProgrammer = new Programmer() {
@Override
public void code() {
// TODO Auto-generated method stub
System.out.println("Php programmer");
}
};
phpProgrammer.code();
}
}
(3)、參數(shù)式的匿名內(nèi)部類
public interface Programmer {
public void code();
}
public class TestProgrammer1 {
public void testCode(Programmer p) {
p.code();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
TestProgrammer1 testProgrammer1 = new TestProgrammer1();
testProgrammer1.testCode(new Programmer() {
@Override
public void code() {
// TODO Auto-generated method stub
System.out.println("testing code");
}
});
}
}
典型的情況是,內(nèi)部類繼承自某個(gè)類或?qū)崿F(xiàn)某個(gè)接口,內(nèi)部類的代碼操作創(chuàng)建其的外圍類的對(duì)象。所以你可以認(rèn)為內(nèi)部類提供了某種進(jìn)入其外圍類的窗口。
使用內(nèi)部類最吸引人的原因是:
使用內(nèi)部類最吸引人的原因是:
每個(gè)內(nèi)部類都能獨(dú)立地繼承自一個(gè)(接口的)實(shí)現(xiàn),所以無論外圍類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn),對(duì)于內(nèi)部類都沒有影響。如果沒有內(nèi)部類提供的可以繼承多個(gè)具體的或抽象的類的能力,一些設(shè)計(jì)與編程問題就很難解決。從這個(gè)角度看,內(nèi)部類使得多重繼承的解決方案變得完整。接口解決了部分問題,而內(nèi)部類有效地實(shí)現(xiàn)了“多重繼承”。
posted on 2014-08-01 17:34 小羅 閱讀(201) 評(píng)論(0) 編輯 收藏