现在的位置: 首页 > 综合 > 正文

Java内部类(Inner Class)详解

2013年10月20日 ⁄ 综合 ⁄ 共 9568字 ⁄ 字号 评论关闭

重新来认识一下内部类的区别

1         

Static 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自身使用。
2         

Member class(成员类)
一个静态成员类,若去掉“static”关键字,就成为成员类。如下示例代码,Inner1/Inner2/Inner3/Inner4就是Outer的四个成员类
 

public
 class
 Outer {
    

//
just like instance method, member class has public/private/default access privilege levels


    
private
 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: default


    
class
 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 class


    
interface
 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开放额外的访问接口。
3         

Local 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 block


    
static
 {
        

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 method


        
class
 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 method


        
class
 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     

什么时候使用局部类
局部类大部分以匿名类的形式使用。
           
4         

Anonymous 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 it


        
new
 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!

抱歉!评论已关闭.