天天看點

靜态嵌套類(Static Nested Class)和内部類(Inner Class)

一. 什麼是嵌套類及内部類?

可以在一個類的内部定義另一個類, 這種類稱為嵌套類(nested classes),它有兩種類型:

靜态嵌套類和非靜态嵌套類.靜态嵌套類使用很少, 最重要的是非靜态嵌套類, 也即是被稱作為

内部類(inner).嵌套類從JDK1.1開始引入.其中inner類又可分為三種:

(1) 在一個類(外部類)中直接定義的内部類;

(2) 在一個方法(外部類的方法)中定義的内部類;

(3) 匿名内部類.

下面, 我将說明這幾種嵌套類的使用及注意事項.

二. 靜态嵌套類

如下所示代碼為定義一個靜态嵌套類

package inner;

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;

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;

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();

   }

}