Java內部類總結[轉]

Java內部類總結
 
Java內部類其實在J2EE編程中使用較少,不過在窗口應用編程中特別常見,主要用來事件的處理。其實,做非GUI編程,內部類完全可以不用。
 
內部類的聲明、訪問控制等於外部類有所不同,要靈活使用內部類來編寫程序,還是有相當難度的,Java發明了這種難懂的玩意兒,在其他語言中是沒有的,但是在Java中,內部類也相當的重要,尤其做GUI開發時候,事件的響應處理全靠內部類了。
 
內部類所做的功能使用外部類也同樣可以實現,只是有時候內部類做的更巧妙些。
 
內部類按照其所在位置不同,可分爲以下幾種:
1、(普通的)內部類(最常見的內部類,內部類的定義與類成員平級,)
2、方法內部類
3、匿名類
4、靜態內部類
5、接口內部類
 
一、內部類聲明與訪問
 
1、內部類直接在類的內部進行聲明。可以聲明爲private、protected、public或者默認訪問權限,這個訪問權限約定和外部類完全一樣。
 
2、內部類自動擁有對其外圍類所有成員(方法、屬性)的訪問權。如果內部類和外部類成員的名字完全相同,在內部類方法中要訪問外部類成員,則需要使用下面的方式來訪問:外部類名.this.外部成員名,例如Outer.this.i++;  (看例子)
 
3、必須使用外部類對象來創建內部類對象,而不是直接去new一個。
格式爲:外部對象名.new 內部類構造方法
 
比如要創建一個內部類iner對象,需要這麼做:
        Outer outer = new Outer();
        Outer.Inner iner = outer.new Inner();
 
/** 
* 內部類創建與初始化 

* @author leizhimin 2009-7-17 13:51:52 
*/
 
public class Outer { 
        private int i = 10; 
        private int y = 8; 

        Outer() { 
                System.out.println("調用Outer構造方法:outer"); 
        } 

        public void sayMsg() { 
                System.out.println("Outer class!"); 
        } 

        class Inner { 
                int i = 1000; 

                Inner() { 
                        System.out.println("調用Inner構造方法:inner"); 
                } 

                void innerMsg() { 
                        System.out.println(">>>>>Inner class!"); 
                        sayMsg(); 
                        //訪問內部類自己的成員i,也可以寫成 this.i++ 
                        this.i++; 
                        //訪問外部類的成員 i和y 
                        Outer.this.i++; 
                        y--; 
                } 

                int getI() { 
                        return i; 
                } 
        } 

        public void test() { 
                Inner in = new Inner(); 
                in.innerMsg(); 
        } 

        public int getI() { 
                return i; 
        } 

        public void setI(int i) { 
                this.i = i; 
        } 


class Test1 { 
        public static void main(String[] args) { 
                Outer outer = new Outer(); 
                outer.test(); 
                System.out.println(outer.getI()); 
                System.out.println("-------1--------"); 

                Outer.Inner iner = outer.new Inner(); 
                iner.innerMsg(); 
                System.out.println(iner.getI()); 
                System.out.println("-------2--------"); 

                System.out.println(outer.getI()); 
        } 
}
 
運行結果:
調用Outer構造方法:outer 
調用Inner構造方法:inner 
>>>>>Inner class
Outer class
11 
-------1-------- 
調用Inner構造方法:inner 
>>>>>Inner class
Outer class
1001 
-------2-------- 
12 

Process finished with exit code 0
 
二、內部類與接口
 
1、內部類可以實現接口。
2、內部類之間相互可見,但並非內部類之間方法都可見。
 
public interface Foo{ 
         void say(); 
}
 
public interface Bar { 
        void readme(); 
}
 
/** 
* 內部類實現接口 

* @author leizhimin 2009-7-17 14:57:50 
*/
 
public class Test2 { 
        public static void main(String[] args) { 
                Outer outer = new Outer(); 
                Foo f = outer.genFoo(); 
                Bar b = outer.genBar(); 
                f.say(); 
                b.readme(); 
        } 


class Outer { 
        private class FooImpl implements Foo { 
                public void say() { 
                        System.out.println("say foo!"); 
                } 
        } 

        private class BarImpl implements Bar { 
                public void readme() { 
                        System.out.println("say bar!"); 
                } 
        } 

        public Foo genFoo() { 
                return new FooImpl(); 
        } 

        public Bar genBar() { 
                return new BarImpl(); 
        } 
}
 
輸入結果:
say foo! 
say bar! 

Process finished with exit code 0
 
三、訪問權限
 
外部類分兩種:
一種嵌入了內部類聲明代碼外部類,稱爲直接外部類。
另一種是與內部類沒有任何關係的外部類,稱爲外部類。
 
在同一個直接外部類中,內部類之間所有的方法都是相互可見的,包含在直接外部類的main()中可見。

在外部類中,要看到一個類的內部類成員,則至少要求這個內部類的class和成員權限大於或等於protected。
 
/** 
* 內部類實現接口 

* @author leizhimin 2009-7-17 14:57:50 
*/
 
public class Test2 { 
        public static void main(String[] args) { 
                Outer o = new Outer(); 
                Outer.Bar b = o.genBar(); 
                b.readme(); 
        } 


class Outer { 

        protected class Foo { 
                protected void say() { 
                        System.out.println("say foo!"); 
                } 

                private void test() { 
                        System.out.println("----test------"); 
                } 
        } 

        protected class Bar { 
                protected void readme() { 
                        System.out.println("say bar!"); 
                        new Foo().test(); 
                } 
        } 

        public Foo genFoo() { 
                return new Foo(); 
        } 

        public Bar genBar() { 
                return new Bar(); 
        } 
}
 
四、方法內部類
 
方法內部類只在該方法內部可見,方法內部類可以定義在方法中的任何位置。
/** 
* 內部類實現接口 

* @author leizhimin 2009-7-17 14:57:50 
*/
 
public class Test2 { 
        public static void main(String[] args) { 
                Outer outer = new Outer(); 
                Foo f = outer.genFoo(); 
                Bar b = outer.genBar(); 
                f.say(); 
                b.readme(); 
        } 


class Outer { 
        public Foo genFoo() { 
                //方法內的內部類 
                class FooImpl implements Foo { 
                        public void say() { 
                                System.out.println("say foo!"); 
                        } 
                } 
                return new FooImpl(); 
        } 

        public Bar genBar() { 
                Bar b = null
                if (true) { 
                        //任意位置的內部類 
                        class BarImpl implements Bar { 
                                public void readme() { 
                                        System.out.println("say bar!"); 
                                } 
                        } 
                        b = new BarImpl(); 
                } 
                return b; 
        } 
}
 
運行結果:
say foo! 
say bar! 

Process finished with exit code 0
 
五、匿名類
 
匿名類不給出類名,直接定義一個類,通常這個類實現了某種接口或者抽象。匿名類的訪問權限更沒有討論價值了,看個例子就行了。
 
在一些多線程程序中比較常見,有點變態,呵呵。
/** 
* 匿名類. 

* @author leizhimin 2009-7-17 15:56:17 
*/
 
public class Test3 { 
        public Foo f = new Foo() { 
                public void say() { 
                        System.out.println("O(∩_∩)O哈哈~!"); 
                } 
        }; 

        public Foo test() { 
                return new Foo() { 
                        public void say() { 
                                System.out.println("say foo!"); 
                        } 
                }; 
        } 

        public static void main(String[] args) { 
                Test3 t = new Test3(); 
                t.f.say(); 
                t.test().say(); 
        } 


interface Foo { 
        void say(); 
}
 
運行結果:
O(∩_∩)O哈哈~! 
say foo! 

Process finished with exit code 0
 
/** 
* 普通類的匿名初始化 

* @author leizhimin 2009-7-17 16:13:31 
*/
 
public class Fk { 
        private String x; 

        public Fk(String x) { 
                this.x = x; 
        } 

        @Override 
        public String toString() { 
                return "Fk{" + 
                                "x='" + x + '\'' + 
                                '}'; 
        } 


class Test4 { 
        public Fk hehe() { 
                //把後面的一對大括號去掉呢,呵呵 
                return new Fk("fk") { 
                }; 
        } 

        public static void main(String[] args) { 
                Test4 t = new Test4(); 
                Fk f = t.hehe(); 
                System.out.println(f); 
        } 
}
 
運行結果:
Fk{x='fk'} 

Process finished with exit code 0
 
還有一個不得不提的經典實例,來自thining in java,有改動:
interface Service { 
    void method1(); 
    void method2(); 


interface ServiceFactory { 
    Service getService(); 


class Implementation1 implements Service { 
    private Implementation1() {} 
    public void method1() {System.out.println("Implementation1 method1");} 
    public void method2() {System.out.println("Implementation1 method2");} 
    public static ServiceFactory factory = new ServiceFactory() { 
            public Service getService() { 
                return new Implementation1(); 
            } 
        }; 


class Implementation2 implements Service { 
    private Implementation2() {} 
    public void method1() {System.out.println("Implementation2 method1");} 
    public void method2() {System.out.println("Implementation2 method2");} 
    public static ServiceFactory factory = new ServiceFactory() { 
            public Service getService() { 
                return new Implementation2(); 
            } 
        }; 


public class Factories { 
    public static void serviceConsumer(ServiceFactory fact) { 
        Service s = fact.getService(); 
        s.method1(); 
        s.method2(); 
    } 
    public static void main(String[] args) { 
        serviceConsumer(Implementation1.factory); 
        serviceConsumer(Implementation2.factory); 
    } 
}
 
這個應用給了我們很多思考,我就不說了,不同人看了會有不同的感受。
 
內部類的巧妙使用會讓你的代碼很牛,如果要形容下,那就是:沒看懂的時候感覺神出鬼沒,看懂後感覺鬼斧神工。不過這些代碼多了,別人想看懂都難,想看懂你思路就難上加難了。呵呵!
 
六、靜態內部類
 
靜態內部類是static class型的內部類,這種內部類特點是:它不能訪問外部類的非靜態成員。要創建靜態內部類對象時候,也不需要外部類對象了,直接可以:
new 外部類名.內部類構造方法
來創建,給個例子:
/** 
* 靜態內部類 

* @author leizhimin 2009-7-17 16:53:05 
*/
 
public class Outer { 
        public static int i =500; 
        protected static class Inner { 
                int i =100; 
                String name; 

                Inner(String name) { 
                        this.name = name; 
                } 

                void sayHello() { 
                        System.out.println("Hello " + name); 
                        Outer.i++; 
                } 
        } 

        public Inner genInner(String name) { 
                return new Inner(name); 
        } 


class Test { 
        public static void main(String[] args) { 
                Outer.Inner in1 = new Outer.Inner("1111"); 
                in1.sayHello(); 
                System.out.println(Outer.i); 

                Outer.Inner in2 = new Outer().genInner("2222"); 
                in2.sayHello(); 
                System.out.println(Outer.i); 
        } 
}
 
運行結果:
Hello 1111 
501 
Hello 2222 
502 

Process finished with exit code 0
 
七、接口內部類
 
接口內部類自動都是public static的,相當於爲接口定義了一種變量類型,這在java的設計中就有使用,比如在HashMap中,就有:
static class Entry<K,V> implements Map.Entry<K,V>
 
下面我給個例子,
/** 
* 接口內部類 

* @author leizhimin 2009-7-17 17:20:28 
*/
 
public interface AInterface { 
        void readme(); 

        class Inner1 implements AInterface { 
                public void readme() { 
                        System.out.println("我是一個接口內部類"); 
                } 
        } 


class Main { 
        public static void main(String[] args) { 
                AInterface.Inner1 in1 = new AInterface.Inner1(); 
                in1.readme(); 
        } 
}
 
八、內部的類的嵌套
 
所謂內部類嵌套,就是內部類裏面再定義內部類。其實這種用法還真沒見過,試試寫個簡單例子看看吧:
 
/** 
* 嵌套內部類 

* @author leizhimin 2009-7-17 17:33:48 
*/
 
public class Outer { 
        private void f0() { 
                System.out.println("f0"); 
        } 

        class A { 
                private void a() { 
                        f0(); 
                        System.out.println("a"); 
                } 

                class B { 
                        protected void b() { 
                                a(); 
                                System.out.println("b"); 
                        } 
                } 
        } 

class Test{ 
        public static void main(String[] args) { 
                Outer o = new Outer(); 
                Outer.A    a =     o.new A(); 
                Outer.A.B b = a.new B(); 
                b.b(); 
        } 
}
 
運行結果:
f0 



Process finished with exit code 0
 
八、內部類的繼承
 
內部類的繼承,可以繼承內部類,也可以繼承外部類。
/** 
* 內部類的繼承,可以繼承內部類,也可以繼承外部類 

* @author leizhimin 2009-7-22 13:50:01 
*/
 
public class Outer { 
        class Inner { 
                void doSomething() { 
                        System.out.println("Inner doing ..."); 
                } 
        } 

        class Inner2 extends Inner { 
                void doSomething() { 
                        System.out.println("Inner2 doing ..."); 
                } 

                void readme() { 
                        System.out.println("HeHe!"); 
                } 
        } 


class Test { 
        public static void main(String[] args) { 
                Outer outer = new Outer(); 
                Outer.Inner in = outer.new Inner(); 
                Outer.Inner2 in2 = outer.new Inner2(); 
                in.doSomething(); 
                in2.doSomething(); 
                in2.readme(); 
        } 
}
 
運行結果:
Inner doing ... 
Inner2 doing ... 
HeHe! 

Process finished with exit code 0
 
 
總結:
 
內部類是Java中最複雜深奧的概念之一,而且內部類在訪問控制,修飾符,繼承,實現,抽象,序列化等等很多方面都是一個很讓人迷惑的問題,在實際中,這些問題也許永遠沒機會沒時間搞清,但是一般說來,懂得以上的內部類的知識就足夠用了。
 
內部類的設計也許是彌補Java語言本身的先天不足吧,作爲語言來說,這個特性太變態了點,難道就沒別的法了?
 
以上的總結完全是建立在實踐基礎上的,所列舉的例子也許偏頗,不能全面反映問題的本質,希望有興趣的博友多多發表自己的看法與觀點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章