1. 程式人生 > >Java內部類(Inner Class)詳解

Java內部類(Inner Class)詳解

重新來認識一下內部類的區別

1Static member class(靜態成員類) 類宣告中包含“static”關鍵字的內部類。如以下示例程式碼, Inner1/Inner2/Inner3/Inner4就是Outer的四個靜態成員類。靜態成員類的使用方式與一般頂層類的使用方式基本相同。 public class  Outer{
    
//just like static method, static member class has public/private/default access privilege levels
    
    
//access privilege level: public public
 static class Inner1 {
        
public Inner1() {
            
//Static member inner class can access static method of outer class            staticMethod();    
            
//Compile error: static member inner class can not access instance method of outer class
            
//instanceMethod();          }
    }
    
    
//access privilege level: default static class Inner2 {
        
    }
    
    
//access privilege level: private private static class Inner3 {
        
//define a nested inner class in another inner class public static class Inner4 {    
        }
    }

    
private static void staticMethod() {
        
//cannot define an inner class in a method
/*public static class Inner4() {
        }
*/
    }
    
    
private void instanceMethod() {
        
//private static member class can be accessed only in its outer class definition scope        Inner3 inner3 = new Inner3();
        
//how to use nested inner class        Inner3.Inner4 inner4 = new Inner3.Inner4();
    }
}

class Test {
    Outer.Inner1 inner1 
= new Outer.Inner1();
    
//Test and Outer are in the same package, so Inner2 can be accessed here    Outer.Inner2 inner2 = new Outer.Inner2(); 
    
//Compile error: Inner3 cannot be accessed here
    
//Outer.Inner3 inner3 = new Outer.Inner3(); } 1.1靜態成員類特性

靜態成員類可訪問外部類的任一靜態欄位或靜態方法

像靜態方法或靜態欄位一樣,靜態成員類有public/private/default許可權修飾符

1.2靜態成員類約束

靜態成員類不能與外部類重名

像外部類的靜態方法一樣,不能直接訪問外部類的例項欄位和例項方法

靜態成員類只能定義於外部類的頂層程式碼或外部類其它靜態成員類的頂層程式碼中(巢狀定義);不能定義於外部類的某個函式中。

1.3新增語法     如示例程式碼所示,可以以“OuterClass.InnerClass”的方式來引用某個內部類。 1.4什麼時候使用靜態成員類 B為A的輔助類,且只為A所用時,可將B定義為A的靜態成員類。例如JDK中的LinkedList類就有Entry靜態成員類: public class LinkedList<E> extends AbstractSequentialList<E> 
   …;
   
private static class Entry<E> {
    E element;
    Entry
<E> next;
    Entry
<E> previous;

    Entry(E element, Entry
<E> next, Entry<E> previous) {
        
this.element = element;
        
this.next = next;
        
this.previous = previous;
    }
    }
    …;
}
   顯然,Entry用來表示LinkedList中的一個結點,只被LinkedList自身使用。 2Member class(成員類) 一個靜態成員類,若去掉“static”關鍵字,就成為成員類。如下示例程式碼,Inner1/Inner2/Inner3/Inner4就是Outer的四個成員類
 
public class Outer {
    
//just like instance method, member class has public/private/default access privilege levelsprivate int data;
    
    
//access privilege level: public public class Inner1 {
        
private int data;
        
private int data1;
        
public Inner1() {
            
//member class can access its outer class' instance field directly            data1 = 1;
            
//itself data field            data = 1;
            
//its outer class instance field            Outer.this.data = 1;
        }
    }
    
    
//access privilege level: defaultclass Inner2 {
        
//can not define static filed, method, class in member class
        
//static int j = 1;
        
        
//but, "static final" compound is allowed static final int CONSTANT = 1;
    }
    
    
//access privilege level: private private class Inner3 {
        
public class Inner4 {
            
        }
    }
    
    
//in fact, Inner5 is not a member class but a static member classinterface Inner5 {
    }
    
    
private static void staticMethod() {
        
//can not create a member class instance directly in outer class' static method
        
//Inner1 inner1 = new Inner1();    }
    
    
private void instanceMethod() {
        
//can create a member class instance in outer class' instance method        Inner1 inner1 = new Inner1();
    }
}

class Test {
    
public Test() {
        
//cannot create member class instance directly in class other than outer class
        
//Outer.Inner2 inner2 = new Outer.Inner2();
        
        
//create a member class instance outside it's outer class        Outer outer = new Outer();
        Outer.Inner1 inner1 
= outer.new Inner1();
    }
}
2.1成員類特性 ·類似於外部類的例項函式,成員類有public/private/default許可權修飾符 ·一個成員類例項必然所屬一個外部類例項,成員類可訪問外部類的任一個例項欄位和例項函式。 2.2成員類約束

成員類不能與外部類重名

不能在成員類中定義static欄位、方法和類(static final形式的常量定義除外)。因為一個成員類例項必然與一個外部類例項關聯,這個static定義完全可以移到其外部類中去

成員類不能是介面(interface)。因為成員類必須能被某個外部類例項例項化,而介面是不能例項化的。事實上,如示例程式碼所示,如果你以成員 類的形式定義一個介面,該介面實際上是一個靜態成員類,static關鍵字對inner interface是內含(implicit)的。

2.3新增語法     一個成員類例項必然所屬於其外部類的一個例項,那麼如何在成員類內部獲得其所屬外部類例項呢?如示例程式碼所示,採用“OuterClass.this”的形式。 2.4指定內部類例項所屬的外部類例項 內部類例項可在其外部類的例項方法中建立,此新建立內部類例項所屬的外 部類例項自然就是建立它的外部類例項方法對應的外部類例項。           另外,如示例程式碼所示,對於給定的一個外部類例項outerClass,可以直接建立其內部類例項,語法形式為:
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
2.5什麼時候使用成員類      成員類的顯著特性就是成員類能訪問它的外部類例項的任意欄位與方法。方便一個類對外提供一個公共介面的實現是成員類的典型應用。        以JDK Collection類庫為例,每種Collection類必須提供一個與其對應的Iterator實現以便客戶端能以統一的方式遍歷任一 Collection例項。每種Collection類的Iterator實現就被定義為該Collection類的成員類。例如JDK中 AbstractList類的程式碼片斷: public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    
private class Itr implements Iterator<E> {
         ………;
    }

     
public Iterator<E> iterator() {
        
return new Itr();
     }
}

    因為定義在AbstractList中的Itr可訪問AbstractList中的任意欄位和方法,所以很方便實現Iterator,無需AbstractList對外暴露更多的介面。     試想,如果沒有成員類機制,只有在AbastractList原始碼之外定義一個實現Iterator的類Itr,該類有一個AbstractList例項 成員list,為了Itr能獲取list的內部資訊以便實現遍歷,AbstractList必然要向Itr開放額外的訪問介面。 3Local class(區域性類) 對一個靜態成員類,去掉其宣告中的“static”關鍵字,將其定義移入其外部類 的靜態方法或靜態初始化程式碼段中就成為了區域性靜態成員類。        對一個成員類,將其定義移入其外部類的例項方法或例項初始化程式碼中就成為了區域性成員類。        區域性靜態成員類與靜態成員類的基本特性相同。例如,都只能訪問外部類的靜態欄位或方法,但不能訪問外部類的例項欄位和例項方法等。        區域性成員類與成員類的基本特性相同。例如,區域性成員類例項必屬於其外部類的一個例項,可通過OuterClass.this引用其外部類例項等。 另外,區域性類也有其自己的特性,如以下程式碼所示:
public class Outer {
    
private int instanceField; 
    
private static int staticField; 
    
    
//define a local member class in instance code block    {
        
int localVirable1 = 0;
        
final int localVirable2 = 1;
        
class Inner1 {
            
public Inner1() {
                
//can access its outer class' field and method directly                instanceField = 1;
                
//use OuterClass.this to get its corresponding outer class instance                Outer.this.instanceField = 1;
                
                
//can not access the not final local virable in its containing code block
                
//System.out.print(localVirable1);
                
                
//can access the final local virable in its containing code block                System.out.print(localVirable2);
            }
        }        
        
        
//local class can not have privilege modifier /*public class inner2 {            
        }
*/
    }
    
    
// define a local static member class in static code blockstatic {
        
class Inner2 {
            
public Inner2() {
                staticField 
= 1;
                
//can not access instance field and method in a local static member class 
                
//intanceField = 2;            }
        }
    }
    
    
public void intanceMethod() {
        
//define a local class in its out class' instance methodclass Inner3 {
        }
        
        
//local class is visible only in its containning code block
        
//Outer.Inner2 inner2;    }
    
    
private static void staticMethod() {
        
//define a local static member class in its out class' static methodclass Inner4 {    
            
public Inner4() {
                staticField 
= 2;
            }
        }
        
        
//can not define a interface as a local class/*interface I {
        }
*/
    }
}

3.1區域性類特性 如示例程式碼所示,區域性類能且只能訪問其所屬程式碼段中的宣告為final的區域性 變數。為什麼只能訪問宣告為final的區域性變數呢?我們知道,區域性變數在其所屬的程式碼段(譬如某個函式)執行完畢後就會被回收,而一個區域性類 的例項卻可以在其類定義所屬程式碼段執行完畢後依然存在,如果它可操控非final的區域性變數,使用者就可以通過該例項修改已不存在的區域性變數,無意義。 3.2區域性類約束

如示例程式碼所示,內部類只在定義它的程式碼段中可見,不能在它所屬程式碼段之外的程式碼中使用;因此也就沒有public/private/default許可權修飾符(無意義)

不能以區域性類形式定義一個介面。區域性類只在其所屬程式碼段中可見,定義這樣的介面無意義

區域性類類名不能與其外部類類名重複

3.3什麼時候使用區域性類 區域性類大部分以匿名類的形式使用。 4Anonymous class(匿名類) 沒有類名的區域性類就是匿名類。用一條語句完成匿名類的定義與例項建立。例 如如下程式碼: public class Outer {
    
public void instanceMethod() {
        
//define a nonymous class which implements Action interface and creat an instance of it        Action action = new Action() {
            
public void doAction() {
                System.out.println(
"a simple anonymous class demo");
            }};
        action.doAction();
        
        
//define a nonoymous class which extends BaseClass and create an instance of itnew BaseClass(5) {
            
public void printData(){
                System.out.println(
"data = " + getData());
            }
        }.printData(); 
//"data = 5" will be outputed    }
}

interface Action {
    
void doAction();
}

class BaseClass {
    
private int data;
    
    
public BaseClass (int data) {
        
this.data = data;
    }
    
    
public int getData() {
        
return data;
    }
}
4.1匿名類特性與約束 匿名類是一種特殊的區域性類。區域性類的特性與約束都適用與它。 4.2新增語法 4.2.1繼承自某個基類的匿名類
new class-name ( [ argument-list ] ) { class-body }
建立匿名類例項時,“argument-list”將被傳入其基類(即class-name)對應的建構函式。 4.2.2實現某個介面的匿名類
new interface-name () { class-body }
4.3什麼時候使用匿名類

該類定義程式碼段很短

只需要建立該類的一個例項

類的定義程式碼與類的使用程式碼緊鄰

使用匿名不影響程式碼的易讀性

譬如,如下實現類似與c的callback功能的程式碼就是匿名類的典型應用: File f = new File("/src");      // The directory to list

// Now call the list() method with a single FilenameFilter argument
// Define and instantiate an anonymous implementation of FilenameFilter
// as part of the method invocation expression. String[] filelist = f.list(new FilenameFilter() {
  
public boolean accept(File f, String s) { return s.endsWith(".java"); }
}); 
// Don't forget the parenthesis and semicolon that end the method call!