1. 程式人生 > 實用技巧 >Java 內部類種類及使用解析

Java 內部類種類及使用解析

內部類Inner Class

  將相關的類組織在一起,從而降低了名稱空間的混亂。

  一個內部類可以定義在另一個類裡,可以定義在函式裡,甚至可以作為一個表示式的一部分。

  Java中的內部類共分為四種:

  靜態內部類static inner class (also called nested class)

  成員內部類member inner class

  區域性內部類local inner class

  匿名內部類anonymous inner class

靜態內部類Static Inner Class

  最簡單的內部類形式。

  類定義時加上static關鍵字。

  不能和外部類有相同的名字。

  被編譯成一個完全獨立的.class檔案,名稱為OuterClass$InnerClass.class的形式。

  只可以訪問外部類的靜態成員和靜態方法,包括了私有的靜態成員和方法。

  生成靜態內部類物件的方式為:

  OuterClass.InnerClass inner = new OuterClass.InnerClass();

  靜態內部類使用程式碼:

 1 package com.learnjava.innerclass;
 2 
 3 class StaticInner
 4 {
 5     private static int a = 4;
 6 
 7     // 靜態內部類
8 public static class Inner 9 { 10 public void test() 11 { 12 // 靜態內部類可以訪問外部類的靜態成員 13 // 並且它只能訪問靜態的 14 System.out.println(a); 15 } 16 17 } 18 } 19 20 public class StaticInnerClassTest 21 { 22 23 public static void main(String[] args)
24 { 25 StaticInner.Inner inner = new StaticInner.Inner(); 26 inner.test(); 27 } 28 }

成員內部類Member Inner Class

  成員內部類也是定義在另一個類中,但是定義時不用static修飾。

  成員內部類和靜態內部類可以類比為非靜態的成員變數和靜態的成員變數。

  成員內部類就像一個例項變數。

  它可以訪問它的外部類的所有成員變數和方法,不管是靜態的還是非靜態的都可以。

  在外部類裡面建立成員內部類的例項:

  this.new Innerclass();

  在外部類之外建立內部類的例項:

  (new Outerclass()).new Innerclass();

  在內部類裡訪問外部類的成員:

  Outerclass.this.member

  詳情見程式碼例子:

 1 package com.learnjava.innerclass;
 2 
 3 class MemberInner
 4 {
 5     private int d = 1;
 6     private int a = 2;
 7 
 8     // 定義一個成員內部類
 9     public class Inner2
10     {
11         private int a = 8;
12 
13         public void doSomething()
14         {
15             // 直接訪問外部類物件
16             System.out.println(d);
17             System.out.println(a);// 直接訪問a,則訪問的是內部類裡的a
18 
19             // 如何訪問到外部類裡的a呢?
20             System.out.println(MemberInner.this.a);
21         }
22 
23     }
24 
25 }
26 
27 public class MemberInnerClassTest
28 {
29 
30     public static void main(String[] args)
31     {
32 
33         // 建立成員內部類的物件
34         // 需要先建立外部類的例項
35         MemberInner.Inner2 inner = new MemberInner().new Inner2();
36 
37         inner.doSomething();
38     }
39 }

區域性內部類Local Inner Class

  區域性內部類定義在方法中,比方法的範圍還小。是內部類中最少用到的一種型別。

  像區域性變數一樣,不能被public, protected, private和static修飾。

  只能訪問方法中定義的final型別的區域性變數。

  區域性內部類在方法中定義,所以只能在方法中使用,即只能在方法當中生成區域性內部類的例項並且呼叫其方法。

 1 package com.learnjava.innerclass;
 2 
 3 class LocalInner
 4 {
 5     int a = 1;
 6 
 7     public void doSomething()
 8     {
 9         int b = 2;
10         final int c = 3;
11         // 定義一個區域性內部類
12         class Inner3
13         {
14             public void test()
15             {
16                 System.out.println("Hello World");
17                 System.out.println(a);
18 
19                 // 不可以訪問非final的區域性變數
20                 // error: Cannot refer to a non-final variable b inside an inner
21                 // class defined in a different method
22                 // System.out.println(b);
23 
24                 // 可以訪問final變數
25                 System.out.println(c);
26             }
27         }
28 
29         // 建立區域性內部類的例項並呼叫方法
30         new Inner3().test();
31     }
32 }
33 
34 public class LocalInnerClassTest
35 {
36     public static void main(String[] args)
37     {
38         // 建立外部類物件
39         LocalInner inner = new LocalInner();
40         // 呼叫外部類的方法
41         inner.doSomething();
42     }
43 
44 }

匿名內部類Anonymous Inner Class

  匿名內部類就是沒有名字的區域性內部類,不使用關鍵字class, extends, implements, 沒有構造方法。

  匿名內部類隱式地繼承了一個父類或者實現了一個介面。

  匿名內部類使用得比較多,通常是作為一個方法引數。

 1 package com.learnjava.innerclass;
 2 
 3 import java.util.Date;
 4 
 5 public class AnonymouseInnerClass
 6 {
 7 
 8     @SuppressWarnings("deprecation")
 9     public String getDate(Date date)
10     {
11         return date.toLocaleString();
12 
13     }
14 
15     public static void main(String[] args)
16     {
17         AnonymouseInnerClass test = new AnonymouseInnerClass();
18 
19         // 列印日期:
20         String str = test.getDate(new Date());
21         System.out.println(str);
22         System.out.println("----------------");
23 
24         // 使用匿名內部類
25         String str2 = test.getDate(new Date()
26         {
27         });// 使用了花括號,但是不填入內容,執行結果和上面的完全一致
28             // 生成了一個繼承了Date類的子類的物件
29         System.out.println(str2);
30         System.out.println("----------------");
31 
32         // 使用匿名內部類,並且重寫父類中的方法
33         String str3 = test.getDate(new Date()
34         {
35 
36             // 重寫父類中的方法
37             @Override
38             @Deprecated
39             public String toLocaleString()
40             {
41                 return "Hello: " + super.toLocaleString();
42             }
43 
44         });
45 
46         System.out.println(str3);
47     }
48 }

  生成的.class檔案中,匿名類會生成OuterClass$1.class檔案,數字根據是第幾個匿名類而類推。

  Swing中使用內部類的例子如下:

 1 package com.learnjava.innerclass;
 2 
 3 import java.awt.event.ActionEvent;
 4 import java.awt.event.ActionListener;
 5 import java.awt.event.WindowAdapter;
 6 import java.awt.event.WindowEvent;
 7 
 8 import javax.swing.JButton;
 9 import javax.swing.JFrame;
10 
11 public class SwingTest
12 {
13     public static void main(String[] args)
14     {
15         JFrame frame = new JFrame("JFrame");
16         JButton button = new JButton("JButton");
17 
18         button.addActionListener(new ActionListener()
19         {
20             // new出來一個實現了ActionListener介面的類的例項
21 
22             @Override
23             public void actionPerformed(ActionEvent arg0)
24             {
25                 System.out.println("Hello World");
26 
27             }
28         });
29 
30         //加入按鈕
31         frame.getContentPane().add(button);
32 
33         //設定關閉行為
34         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
35 
36         frame.setSize(200, 200);
37         
38         frame.addWindowListener(new WindowAdapter()
39         {
40             //也可以使用繼承了介面卡類的匿名內部類
41             @Override
42             public void windowClosing(WindowEvent e)
43             {
44             
45                 System.out.println("Closing");
46                 System.exit(0);
47             }
48         });
49         frame.setVisible(true);
50     }
51 
52 }