內(nèi)部類基礎(chǔ)
- 1 定義
將一個類定義在另一個類里面或者一個方法里面诗力,這樣的類稱為內(nèi)部類妻导。 - 2 分類
廣泛意義上的內(nèi)部類一般來說包括這四種:
1)成員內(nèi)部類
2)局部內(nèi)部類
3)匿名內(nèi)部類
4)靜態(tài)內(nèi)部類
四種內(nèi)部類簡介
- 1 成員內(nèi)部類
1)成員內(nèi)部類是最普通的內(nèi)部類句携,它的定義為位于另一個類的內(nèi)部,形如下面的形式:
public class Circle {
private double radius = 0;
public static int count =1;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //內(nèi)部類
public void drawSahpe() {
System.out.println(radius); //外部類的private成員
System.out.println(count); //外部類的靜態(tài)成員
}
}
}
2)類Draw像是類Circle的一個成員屿衅,所以Draw類稱為成員內(nèi)部類蝎毡,Circle類稱為外部類。
3)成員內(nèi)部類可以無條件訪問外部類的所有成員屬性和方法(包括private和static修飾的)。
4)當成員內(nèi)部類擁有和外部類同名的成員變量或者方法時,會發(fā)生隱藏現(xiàn)象卷扮,即默認情況下訪問的是成員內(nèi)部類的成員荡澎。如果要訪問外部類的同名成員,需要以下面的形式進行訪問:
Circle.this.radius;
5)在外部類中如果要訪問成員內(nèi)部類的成員晤锹,必須先創(chuàng)建一個成員內(nèi)部類的對象摩幔,再通過指向這個對象的引用來訪問:
public class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
getDrawInstance().drawSahpe(); //必須先創(chuàng)建成員內(nèi)部類的對象,再進行訪問
}
private Draw getDrawInstance() {
return new Draw();
}
class Draw { //內(nèi)部類
public void drawSahpe() {
System.out.println(radius); //外部類的private成員
}
}
}
6)另一種創(chuàng)建成員內(nèi)部類的語法如下:
public class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //內(nèi)部類
public void drawSahpe() {
System.out.println("sheep");
}
}
public static void main(String[] args) {
Circle circle = new Circle();
Draw drow = circle.new Draw(); //必須通過circle對象來創(chuàng)建
}
}
- 2 局部內(nèi)部類
1)局部內(nèi)部類是定義在一個方法或者一個作用域里面的類鞭铆,它和成員內(nèi)部類的區(qū)別在于局部內(nèi)部類的訪問僅限于方法內(nèi)或者該作用域內(nèi)或衡。
public class People{
public People() {
}
}
public class Man{
public Man()
}
public People getWoman(){
class Woman extends People{ //局部內(nèi)部類
int age =0;
}
return new Woman();
}
}
2)局部內(nèi)部類就像是方法里面的一個局部變量一樣焦影,是不能有public、protected封断、private以及static修飾符的斯辰。
- 3 匿名內(nèi)部類
1)匿名內(nèi)部類應(yīng)該是平時我們編寫代碼時用得最多的,在編寫事件監(jiān)聽的代碼時使用匿名內(nèi)部類不但方便坡疼,而且使代碼更加容易維護彬呻。
new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
2)匿名內(nèi)部類是唯一一種沒有構(gòu)造器的類。正因為其沒有構(gòu)造器柄瑰,所以匿名內(nèi)部類的使用范圍非常有限闸氮,大部分匿名內(nèi)部類用于接口回調(diào)。匿名內(nèi)部類在編譯的時候由系統(tǒng)自動起名為Outter$1.class教沾。
3)一般來說蒲跨,匿名內(nèi)部類用于繼承其他類或是實現(xiàn)接口,并不需要增加額外的方法授翻,只是對繼承方法的實現(xiàn)或是重寫或悲。
- 4 靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類也是定義在另一個類里面的類,只不過在類的前面多了一個關(guān)鍵字static藏姐。
2)靜態(tài)內(nèi)部類是不需要依賴于外部類的隆箩,這點和類的靜態(tài)成員屬性有點類似,并且它不能使用外部類的非static成員變量或者方法羔杨,這點很好理解捌臊,因為在沒有外部類的對象的情況下,可以創(chuàng)建靜態(tài)內(nèi)部類的對象兜材,如果允許訪問外部類的非static成員就會產(chǎn)生矛盾理澎,因為外部類的非static成員必須依附于具體的對象。
public class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner(); // 不需要先創(chuàng)建外部類的實例
}
}
深入理解內(nèi)部類
- 1 為什么成員內(nèi)部類可以無條件訪問外部類的成員曙寡?
1)編譯器會默認為成員內(nèi)部類添加了一個指向外部類對象的引用糠爬。
2)雖然我們在定義的內(nèi)部類的構(gòu)造器是無參構(gòu)造器,編譯器還是會默認添加一個參數(shù)举庶,該參數(shù)的類型為指向外部類對象的一個引用
3)從這里也間接說明了成員內(nèi)部類是依賴于外部類的执隧,如果沒有創(chuàng)建外部類的對象,則無法對Outter this&0引用進行初始化賦值户侥,也就無法創(chuàng)建成員內(nèi)部類的對象了镀琉。 - 2 為什么局部內(nèi)部類和匿名內(nèi)部類只能訪問局部final變量?
public class Test {
public static void main(String[] args) {
}
public void test(final int b) {
final int a = 10;
new Thread(){
public void run() {
System.out.println(a);
System.out.println(b);
};
}.start();
}
}
1)當test方法執(zhí)行完畢之后蕊唐,變量a的生命周期就結(jié)束了屋摔,而此時Thread對象的生命周期很可能還沒有結(jié)束,那么在Thread的run方法中繼續(xù)訪問變量a就變成不可能了替梨,但是又要實現(xiàn)這樣的效果钓试,怎么辦呢装黑?Java采用了 復制 的手段來解決這個問題。
2)這個過程是在編譯期間由編譯器默認進行弓熏,如果這個變量的值在編譯期間可以確定恋谭,則編譯器默認會在匿名內(nèi)部類(局部內(nèi)部類)的常量池中添加一個內(nèi)容相等的字面量或直接將相應(yīng)的字節(jié)碼嵌入到執(zhí)行字節(jié)碼中。這樣一來硝烂,匿名內(nèi)部類使用的變量是另一個局部變量箕别,只不過值和方法中局部變量的值相等,因此和方法中的局部變量完全獨立開滞谢。
3)既然在run方法中訪問的變量a和test方法中的變量a不是同一個變量串稀,當在run方法中改變變量a的值的話,會出現(xiàn)什么情況狮杨?
4)對母截,會造成數(shù)據(jù)不一致性,這樣就達不到原本的意圖和要求橄教。為了解決這個問題清寇,java編譯器就限定必須將變量a限制為final變量,不允許對變量a進行更改(對于引用類型的變量护蝶,是不允許指向新的對象)华烟,這樣數(shù)據(jù)不一致性的問題就得以解決了。到這里持灰,想必大家應(yīng)該清楚為何 方法中的局部變量和形參都必須用final進行限定了盔夜。
內(nèi)部類的使用場景和好處
- 1 每個內(nèi)部類都能獨立的繼承一個接口的實現(xiàn),所以無論外部類是否已經(jīng)繼承了某個(接口的)實現(xiàn)堤魁,對于內(nèi)部類都沒有影響喂链。內(nèi)部類使得多繼承的解決方案變得完整,
- 2 方便將存在一定邏輯關(guān)系的類組織在一起妥泉,又可以對外界隱藏椭微。
- 3 方便編寫事件驅(qū)動程序
- 4 方便編寫線程代碼