http://android.yaohuiji.com/archives/3247html
本講內容:內部類java
Java語言容許在類中再定義類,這種在其它類內部定義的類就叫內部類。內部類又分爲:常規內部類、局部內部類、匿名內部類和靜態嵌套類四種。咱們內部類的知識在Android手機開發中常常用到。android
1、常規內部類ide
所謂常規內部類,或者說內部類,指的就是除去後面三種以外的內部類(這算什麼解釋。。。)oop
先寫一個最簡單的內部類的例子,你們感受一下:ui
編譯一下,咱們看到目錄中出現了兩個class文件,其中有一個文件名叫作Outer$Inner.class,帶了一個$符號,這個特色讓咱們很容易的認出來這是內部類編譯後的class文件。this
再寫一個稍微複雜一點的內部類:spa
06 |
System.out.println( "Outer initial" ); |
12 |
System.out.println( "Inner initial" ); |
19 |
System.out.println(x); |
20 |
System.out.println( this .x); |
21 |
System.out.println(Outer. this .x); |
26 |
public static void main(String[] args){ |
27 |
Inner inner = new Outer(). new Inner(); |
咱們編譯之後,運行一下看看:.net
在上面的例子裏咱們能夠清晰的看到:code
- 內部類就像一個實例成員同樣存在於外部類中。
- 內部類能夠訪問外部類的全部成員就想訪問本身的成員同樣沒有限制。
- 內部類中的this指的是內部類的實例對象自己,若是要用外部類的實例對象就能夠用類名.this的方式得到。
- 內部類對象中不能有靜態成員,緣由很簡單,內部類的實例對象是外部類實例對象的一個成員。
下面咱們再小結一下內部類的建立方法:
- 在外部類的內部,能夠用 Inner inner = new Inner(); 方法直接建立
- 在外部類外部,必須先建立外 部類實例,而後再建立內部類實例,除了上面 Inner inner = new Outer().new Inner()的寫法之外,還有 Outer outer = new Outer(); Inner inner = outer.new Inner();的寫法
2、局部內部類
咱們也能夠把類定義在方法內部,這時候咱們稱這個類叫局部內部類。
咱們再看一個例子:
04 |
public void doSomething(){ |
10 |
System.out.println(x); |
11 |
System.out.println( this .x); |
12 |
System.out.println(Outer. this .x); |
13 |
System.out.println(y); |
16 |
Inner inner = new Inner(); |
20 |
public static void main(String[] args){ |
21 |
Outer outer = new Outer(); |
運行程序,查看結果:
咱們經過上面這裏例子也能夠看到下面幾點:
- 局部內部類的地位和方法內的局部變量的位置相似,所以不能修飾局部變量的修飾符也不能修飾局部內部類,譬如public、private、protected、static、transient等
- 局部內部類只能在聲明的方法內是可見的,所以定義局部內部類以後,想用的話就要在方法內直接實例化,記住這裏順序不能反了,必定是要先聲明後使用,不然編譯器會說找不到。
- 局部內部類不能訪問定義它的方法內的局部變量,除非這個變量被定義爲final 。
是否是有點很差理解?關於爲何用final修飾之後就能夠用了,我打算專門在番外篇裏專門寫一篇博客給你講清楚,先記住吧。
3、匿名內部類
當咱們把內部類的定義和聲明寫到一塊兒時,就不用給這個類起個類名而是直接使用了,這種形式的內部類根本就沒有類名,所以咱們叫它匿名內部類。
咱們再看一個有趣的例子:
03 |
public interface Pet { |
05 |
public void beFriendly(); |
10 |
public static void main(String[] args){ |
14 |
public void beFriendly() { |
15 |
System.out.println( "蹭蹭你^_^" ); |
19 |
System.out.println( "把飛盤叼給你,逼你把飛盤丟出去,而後它再撿回來讓你繼續扔,連續500次^_^" ); |
編譯和運行程序,查看結果:
居然編譯和運行都很正常,咱們知道抽象類和接口確定沒法實例化的,所以剛纔的例子確定有點意思:
- 第一匿名內部類能夠是個接口,這個沒什麼好奇怪的哈。
- 第12行到第21行是一個語句,就是定義了一個對象,所以21行大括號後面有個分號。
- 匿名內部類用 new Pet(){ … } 的方式把聲明類的過程和建立類的實例的過程合二爲一。
- 匿名內部類能夠是某個類的繼承子類也能夠是某個接口的實現類。
好吧咱們再看一個例子,方法參數內的匿名內部類:
03 |
static abstract class Ball { |
04 |
abstract String getName(); |
08 |
System.out.println(b.getName()); |
11 |
public static void main(String[] args){ |
編譯和運行之後的截圖我就不給你了,返回值就是「qiu qiu」。
從第14行到第18行是一句話,就是執行一個play方法,而這個方法的參數就由一個匿名內部類的實例來提供。
4、靜態嵌套類
爲了讓你感受舒服一些,咱們也把最簡單的內部類放在最後講。
當一個內部類前面用static修飾時,咱們稱之爲靜態嵌套類或者說靜態內部類。
上面的例子裏其實咱們已經看到過靜態嵌套類了,下面咱們再舉一個例子:
08 |
System.out.println( "Nest " +x); |
12 |
public static void main(String[] args){ |
13 |
Outer.Nest nest = new Outer.Nest(); |
由於靜態嵌套類和其餘靜態方法同樣只能訪問其它靜態的成員,而不能訪問實例成員。所以靜態嵌套類和外部類(封裝類)之間的聯繫就不多了,他們之間可 能也就是命名空間上的一些關聯。上面例子中你須要注意的就是靜態嵌套類的聲明方法 new Outer.Nest() 連續寫了兩個類名,以致於咱們都懷疑前面的Outer是個包名了,好在包名通常都小寫的,要不還真分不清……
再強調一遍,內部類在Android中應用的很是多,理解和使用好顯得蠻重要。好了,本講就到這裏。
如何應用Java的靜態內部類
http://java.chinaitlab.com/oop/787330.html
在上一小節咱們討論了內部類,即在一個類中包含有另一個或者多個類(見本書12.3.3小節)。與內部類類似,靜態內部類指在一個類的內部包含有另一個或者多個靜態類。例如:
public class OuterClass {
...
static class StaticInnerClass1 { //內部靜態類
//只能夠訪問OuterClass的靜態成員
...
} //StaticInnerClass結束
...
static class StaticInnerClassN { //更多靜態內部類
//只能夠訪問OuterClass的靜態成員
...
} //StaticInnerClassN結束
} //OuterClass結束
與通常內部類不一樣,在靜態代碼中不可以使用this操做,因此在靜態內部類中只能夠訪問外部類的靜態變量和靜態方法。使用靜態內部類的目的和使用內部類相同。若是一個內部類不依賴於其外部類的實例變量,或與實例變量無關,則選擇應用靜態內部類。
以下例子演示怎樣使用靜態內部類:
///完整程序存在本書配套資源目錄Ch12名爲StaticInnerClassTest.java
public class StaticInnerClassTest {
public static void main( String args[] ) {
OuterClass2 outer = new OuterClass2();
OuterClass2.StaticInnerClass.innerMethod();
//調用靜態內部類的靜態方法
OuterClass2.outerMethod();
//建立靜態內部類對象
OuterClass2.StaticInnerClass staticInner = new OuterClass2.StaticInnerClass();
int num = staticInner.innerMethod2(); //調用靜態內部類實例方法
}
}
class OuterClass2 { //外部類
private double x = 0.0; //內部靜態類不能夠訪問外部類實 例變量
static private int n = 10; //外部類靜態變量
static void outerMethod() { //外部類靜態方法
System.out.println("from OuterClass...");
}
void outerMethod2() {
System.out.println("from OuterClass’ instance method2()...");
}
static class StaticInnerClass { //靜態內部類
static private int m = 5; //靜態內部類靜態變量
static void innerMethod() { //靜態內部類靜態方法
int sum;
n = 20; //只能夠訪問外部類靜態變量
sum = n + m;
System.out.println("from InnerClass sum = " + sum);
outerMethod(); //只能夠調用外部類靜態方法
}
int innerMethod2() {
n = 100;
outerMethod();
System.out.println("from InnerMethod2() n = " + n);
return n;
}
} //靜態內部類結束
} //外部類結束
如同不用建立對象就可調用靜態方法同樣,上例靜態內部類中的靜態方法利用:
OuterClass2.StaticInnerClass.innerMethod(); //靜態內部類調用其靜態方法
來調用。注意,能夠在靜態內部類的方法中,直接訪問外部類的靜態變量n和調用靜態方法outerMethod()。但不容許訪問外部類的實例變量x以及實例方法outerMethod2()。
靜態內部類中也能夠提供實例方法,如:
static class StaticInnerClass {
int innerMethod2() {
n = 100; //只可訪問外部類靜態變量
outerMethod(); //只可調用外部類靜態方法
System.out.println("from InnerMethod2() n = " + n);
return n;
}
} //靜態內部類結束
靜態內部類的實例方法中亦只容許訪問外部類的靜態成員。
可使用下列語法格式建立一個靜態內部類對象而且調用其實例方法,以及靜態方法:
OuterClass2.StaticInnerClass staticInner = new OuterClass2.StaticInner Class(); //建立靜態內部類對象
int num = staticInner.innerMethod2(); //調用實例方法
staticInner.innerMethod(); //調用其靜態方法
- package Chapter10;
- public class StaticInternal {
- private static String name = "\"聶慶亮\"";
- public static void setStatic(String n) {
- System.out.println("[如今訪問的是外部類的靜態方法!]");
- name = n;
- }
- static class InnerClass_2 {
- String address, mail;
- long phoneNum;
- int qq;
- static void getStatic() {
- System.out.println("[訪問外部類的靜態變量] name = " + name);
- setStatic("尹繼平");
- }
-
- public void setString(String address, String mail) {
- System.out.println("1.靜態內部類的帶String型參數的非靜態主法");
- this.address = address;
- this.mail = mail;
- }
- public void setInt(long phoneNum, int qq) {
- System.out.println("2.靜態內部類的帶int型參數的非靜態主法!");
- this.phoneNum = phoneNum;
- this.qq = qq;
- }
- }
- public void setValue() {
- InnerClass_2.getStatic();
- InnerClass_2 inner = new InnerClass_2();
- inner.setString("北京昌平區沙河鎮", "yinjiping@sina.com");
- inner.setInt(89653310, 313557706);
- System.out.println("\n外部類訪問靜態內部類的結果以下:");
- System.out.println("姓名:" + this.name);
- System.out.println("住址:" + inner.address);
- System.out.println("聯繫電話" + inner.phoneNum);
- System.out.println("E-mail:" + inner.mail);
- System.out.println("QQ號碼:" + inner.qq);
- }
- public static void main(String[] args) {
- StaticInternal sin = new StaticInternal();
- sin.setValue();
- }
- }
Java內部類與靜態內部類
定義在一個類內部的類叫內部類,包含內部類的類稱爲外部類。內部類能夠聲明public、protected、private等訪問限制,能夠聲明 爲abstract的供其餘內部類或外部類繼承與擴展,或者聲明爲static、final的,也能夠實現特定的接口。外部類按常規的類訪問方式使用內部 類,惟一的差異是外部類能夠訪問內部類的全部方法與屬性,包括私有方法與屬性。
(1)建立實例
OutClass.InnerClass obj = outClassInstance.new InnerClass(); //注意是外部類實例.new,內部類
AAA.StaticInner in = new AAA.StaticInner();//注意是外部類自己,靜態內部類
(2)內部類中的this
內部類中的this與其餘類同樣是指的自己。建立內部類對象時,它會與創造它的外圍對象有了某種聯繫,因而能訪問外圍類的全部成員,不需任何特殊條 件,可理解爲內部類連接到外部類。 用外部類建立內部類對象時,此內部類對象會祕密的捕獲一個指向外部類的引用,因而,能夠經過這個引用來訪問外圍類的成員。
(3)外部類訪問內部類
內部類相似外部類的屬性,所以訪問內部類對象時老是須要一個建立好的外部類對象。內部類對象經過‘外部類名.this.xxx’的形式訪問外部類的屬性與方法。如:
System.out.println("Print in inner Outer.index=" + pouter.this.index);
System.out.println("Print in inner Inner.index=" + this.index);
(4)內部類向上轉型
內部類也能夠和普通類同樣擁有向上轉型的特性。將內部類向上轉型爲基類型,尤爲是接口時,內部類就有了用武之地。若是內部類是private的,只能夠被它的外部類問,從而徹底隱藏實現的細節。
(5)方法內的類
方法內建立的類(注意方法中也能定義類),不能加訪問修飾符。另外,方法內部的類也不是在調用方法時纔會建立的,它們同樣也被事先編譯了。
(6)靜態內部類
定義靜態內部類:在定義內部類的時候,能夠在其前面加上一個權限修飾符static。此時這個內部類就變爲了靜態內部類。
一般稱爲嵌套類,當內部類是static時,意味着:
[1]要建立嵌套類的對象,並不須要其外圍類的對象;
[2]不能從嵌套類的對象中訪問非靜態的外圍類對象(不可以從靜態內部類的對象中訪問外部類的非靜態成員);
嵌套類與普通的內部類還有一個區別:普通內部類的字段的字段與方法,只能放在類的外部層次上,因此普通的內部類不能有static數據和 static字段,也不能包含嵌套類。可是在嵌套類裏能夠包含全部這些東西。也就是說,在非靜態內部類中不能夠聲明靜態成員,只有將某個內部類修飾爲靜態 類,而後纔可以在這個類中定義靜態的成員變量與成員方法。
另外,在建立靜態內部類時不須要將靜態內部類的實例綁定在外部類的實例上。普通非靜態內部類的對象是依附在外部類對象之中的,要在一個外部類中定義 一個靜態的內部類,不須要利用關鍵字new來建立內部類的實例。靜態類和方法只屬於類自己,並不屬於該類的對象,更不屬於其餘外部類的對象。
(7)內部類標識符
每一個類會產生一個.class文件,文件名即爲類名。一樣,內部類也會產生這麼一個.class文件,可是它的名稱卻不是內部類的類名,而是有着嚴格的限制:外圍類的名字,加上$,再加上內部類名字。
(8)爲什麼要用內部類?
1. 內部類通常只爲其外部類使用;
2. 內部類提供了某種進入外部類的窗戶;
3. 也是最吸引人的緣由,每一個內部類都能獨立地繼承一個接口,而不管外部類是否已經繼承了某個接口。所以,內部類使多重繼承的解決方案變得更加完整。