Java靜態內部類和非內部類的區別

 一. 什麼是嵌套類及內部類?
可以在一個類的內部定義另一個類, 這種類稱爲嵌套類(nested classes),它有兩種類型:
靜態嵌套類和非靜態嵌套類.靜態嵌套類使用很少, 最重要的是非靜態嵌套類, 也即是被稱作爲
內部類(inner).嵌套類從JDK1.1開始引入.其中inner類又可分爲三種:
(1) 在一個類(外部類)中直接定義的內部類;
(2) 在一個方法(外部類的方法)中定義的內部類;
(3) 匿名內部類.
下面, 我將說明這幾種嵌套類的使用及注意事項.

二. 靜態嵌套類
如下所示代碼爲定義一個靜態嵌套類

            
package inner; /** * @author: Joho Woo * @email: [email protected] * @version: 1.0 * @time: 2007-11-12 下午07:52:29 * @description: */ public class StaticTest {    private static String name = "woobo";    private String num = "X001";    static class Person    {      private String address = "China";      public String mail = "[email protected]";//內部類公有成員      public void display()      {        //System.out.println(num);//不能直接訪問外部類的非靜態成員        System.out.println(name);//只能直接訪問外部類的靜態成員        System.out.println("Inner " + address);//訪問本內部類成員。      }    }    public void printInfo()    {      Person person = new Person();      person.display();      //System.out.println(mail);//不可訪問      //System.out.println(address);//不可訪問      System.out.println(person.address);//可以訪問內部類的私有成員      System.out.println(person.mail);//可以訪問內部類的公有成員    }    public static void main(String[] args)    {      StaticTest staticTest = new StaticTest();      staticTest.printInfo();    } }

在靜態嵌套類內部, 不能訪問外部類的非靜態成員, 這是由Java語法中"靜態方法不能直接訪問非靜態成員"所限定.若想訪問外部類的變量, 必須通過其它方法解決, 由於這個原因, 靜態嵌套類使用很少.注意, 外部類訪問內部類的的成員有些特別, 不能直接訪問, 但可以通過內部類實例來訪問, 這是因爲靜態嵌套內的所有成員和方法默認爲靜態的了.同時注意, 內部靜態類Person只在類StaticTest 範圍內可見, 若在其它類中引用或初始化, 均是錯誤的.

三. 在外部類中定義內部類
如下所示代碼爲在外部類中定義兩個內部類及它們的調用關係:

            
class Outer {    int outer_x = 100;    private class InnerOne    {      // 私有的內部類      public int inner_y = 10;      private int inner_z = 9;      int inner_m = 5;      public void display()      {        System.out.println("display outer_x:" + outer_x);      }      private void display2()      {        System.out.println("display outer_x:" + outer_x);      }    }    public InnerOne getInnerOne()    {      // 即使是對外公開的方法,外部類也無法調用      return new InnerOne();    }       class InnerTwo    {      InnerOne innerx = getInnerOne();// 可以訪問      public void show()      {        // System.out.println(inner_y); // 不可訪問Innter的y成員        // System.out.println(Inner.inner_y);   // 不可直接訪問Inner的任何成員和方法        innerx.display();// 可以訪問        innerx.display2();// 可以訪問        System.out.println(innerx.inner_y);// 可以訪問        System.out.println(innerx.inner_z);// 可以訪問        System.out.println(innerx.inner_m);// 可以訪問      }    }       void test()    {      InnerOne inner = new InnerOne();// 可以訪問      inner.display();      inner.display2();      // System.out.println("Inner y:" + inner_y); // 不能訪問內部內變量      System.out.println("Inner y:" + inner.inner_y);// 可以訪問      System.out.println("Inner z:" + inner.inner_z);// 可以訪問      System.out.println("Inner m:" + inner.inner_m);// 可以訪問           InnerTwo innerTwo = new InnerTwo();      innerTwo.show();    } } public class Test {    public static void main(String args[])    {      Outer outer = new Outer();      // Outer.Inner a=outer.getInner();      // Inner類是私有的,外部類不能訪問, 如果Inner類是public ,則可以.      outer.test();    } }


內部類Inner及InnterTwo只在類Outer的作用域內是可知的, 如果類Outer外的任何代碼嘗試初始化類Inner或使用它, 編譯就不會通過.同時, 內部類的變量成員只在內部內內部可見, 若外部類或同層次的內部類需要訪問, 需採用示例程序
中的方法, 不可直接訪問內部類的變量.

四. 在方法中定義內部類
如下所示代碼爲在方法內部定義一個內部類:

            
package inner; /** * @author: Joho Woo * @email: [email protected] * @version: 1.0 * @time: 2007-11-12 下午08:25:33 * @description: */ public class FunOuter {    int out_x = 100;    public void test()    {      class Inner      {        String inner_x = "x";        void display()        {          System.out.println(out_x);        }      }      Inner inner = new Inner();      inner.display();    }    public void showStr(String str)    {      // public String str1 = "test Inner";      // 不可定義, 只允許final修飾      // static String str4 = "static Str";      // 不可定義, 只允許final修飾      String str2 = "test Inner";      final String str3 = "final Str";      class InnerTwo      {        public void testPrint()        {          System.out.println(out_x);          // 可直接訪問外部類的變量          // System.out.println(str); // 不可訪問本方法內部的非final變量          // System.out.println(str2); // 不可訪問本方法內部的非final變量          System.out.println(str3); // 只可訪問本方法的final型變量成員        }      }      InnerTwo innerTwo = new InnerTwo();      innerTwo.testPrint();    }    public void use()    {      // Inner innerObj = new Inner();//此時Inner己不可見了      // System.out.println(Inner.x);//此時Inner己不可見了    }    public static void main(String[] args)    {      FunOuter outer = new FunOuter();      outer.test();    } }


從上面的例程我們可以看出定義在方法內部的內部類的可見性更小, 它只在方法內部
可見, 在外部類(及外部類的其它方法中)中都不可見了.同時, 它有一個特點, 就是方法內的內部類連本方法的成員變量都不可訪問, 它只能訪問本方法的final型成員.同時另一個需引起注意的是方法內部定義成員, 只允許final修飾或不加修飾符, 其它像static等均不可用.

五. 匿名內部類
如下所示代碼爲定義一個匿名內部類:匿名內部類通常用在Java的事件處理上

            
package inner; /** * @author: Joho Woo * @email: [email protected] * @version: 1.0 * @time: 2007-11-12 下午09:01:05 * @description: */ import java.applet.*; import java.awt.event.*; public class AnonymousInnerClassDemo extends Applet {    public void init()    {      addMouseListener(new MouseAdapter()      {        public void mousePressed(MouseEvent me)        {          showStatus("Mouse Pressed!");        }      });    }    public void showStatus(String str)    {      System.out.println(str);    } }

在上面的例子中, 方法addMouseListener接受一個對象型的參數表達式, 於是, 在參數裏, 我們定義了一個匿名內部類,這個類是一個MouseAdapter類型的類, 同時在這個類中定義了一個繼承的方法mousePressed, 整個類做爲一個參數.這個類沒有名稱, 但是當執行這個表達式時它被自動實例化.同時因爲, 這個匿名內部類是定義在AnonymousInnerClassDemo
類內部的, 所以它可以訪問它的方法showStatus.這同前面的內部類是一致的.

六. 內部類使用的其它的問題
通過以上, 我們可以清楚地看出內部類的一些使用方法, 同時, 在許多時候, 內部類是在如Java的事件處理. 或做爲值對象來使用的.同時, 我們需注意最後一個問題, 那就是, 內部類同其它類一樣被定義, 同樣它也可以繼承外部其它包的類和實現外部其它地方的接口.同樣它也可以繼承同一層次的其它的內部類,甚至可以繼承外部類本身.下面我們給出最後一個例子做爲結束:

            
public class Layer {    // Layer類的成員變量    private String testStr = "testStr";    // Person類, 基類    class Person    {      String name;      Email email;      public void setName(String nameStr)      {        this.name = nameStr;      }      public String getName()      {        return this.name;      }      public void setEmail(Email emailObj)      {        this.email = emailObj;      }      public String getEmail()      {        return this.email.getMailStr();      }      // 內部類的內部類, 多層內部類      class Email      {        String mailID;        String mailNetAddress;        Email(String mailId, String mailNetAddress)        {          this.mailID = mailId;          this.mailNetAddress = mailNetAddress;        }        String getMailStr()        {          return this.mailID + "@" + this.mailNetAddress;        }      }    }    // 另一個內部類繼承外部類本身    class ChildLayer extends Layer    {      void print()      {        System.out.println(super.testStr);// 訪問父類的成員變量      }    }    // 另個內部類繼承內部類Person    class OfficePerson extends Person    {      void show()      {        System.out.println(name);        System.out.println(getEmail());      }    }    // 外部類的測試方法    public void testFunction()    {      // 測試第一個內部類      ChildLayer childLayer = new ChildLayer();      childLayer.print(); // 測試第二個內部類      OfficePerson officePerson = new OfficePerson();      officePerson.setName("abner chai");      // 注意此處, 必須用對象.new 出來對象的子類對象      // 而不是Person.new Email(...)      // 也不是new Person.Email(...)      officePerson          .setEmail(officePerson.new Email("josserchai", "yahoo.com"));      officePerson.show();    }    public static void main(String[] args)    {      Layer layer = new Layer();      layer.testFunction();    } }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章