java内部类

可以将一个类的定义放在另一个类的内部,这就是内部类

创建内部类

  • 如果想从外部类的非静态方法之外的任何位置创建某个内部类的对象,必须指明这个对象的类型:OuterClassName.InnerClassName
 1 /**
 2 * 内部类创建
 3 * @author jing.ming
 4 *
 5 */
 6 public class Parcel1 {
 7 class Contents{
 8 private int i=11;
 9 public int value(){
10 return i ;
11 }
12 }
13 class Destination{
14 private String label;
15 Destination(String whereTo){
16 label = whereTo ;
17 }
18 String readLabel(){
19 return label ;
20 }
21 }
22 public Destination to(String s){
23 return new Destination( s);
24 }
25 public Contents contents(){
26 return new Contents() ;
27 }
28 public void ship(){
29 Parcel1 parcel2 = new Parcel1();
30 Parcel1.Contents c= parcel2.contents();
31 Parcel1.Destination d = parcel2.to( "===ShiYan===") ;
32 System. out.println( d.readLabel()) ;
33 System. out.println( c.value()) ;
34 }
35 public static void main(String[] args){
36 Parcel1 parcel= new Parcel1();
37 parcel.ship();
38 }
39 }
 
链接到外部类
到目前为止,内部类似乎还只是一种名字隐藏和组织代码的模式。这些是很有用,但还不是最引人瞩目的,它还有其他的用途。
当生成一个内部类的对象时,此对象与制造他的外围对象之间就有了一种联系,所以他能访问外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外围类的所有元素的访问权
 1 public class Sequence {
 2  
 3      private Object[] items ;
 4      private int next = 0 ;
 5      public Sequence( int size){
 6             items = new Object[ size] ;
 7      }
 8      public void add(Object x){
 9             if( next< items. length){
10                  items[ next++] = x ;
11            }
12      }
13      
14      private class SequenceSelector implements Selector{
15  
16             private int i = 0 ;
17             @Override
18             public boolean isEnd() {
19                  return i== items. length ;
20            }
21  
22             @Override
23             public Object currentObj() {
24                  return items[ i] ;
25            }
26  
27             @Override
28             public void next() {
29                  if( i< items. length) i++ ;        
30            }
31            
32      }
33      
34      public Selector selector(){
35             return new SequenceSelector();
36      }
37      
38      public static void main(String[] args){
39            Sequence sequence = new Sequence(10) ;
40             for( int i =0 ; i<10; i++){
41                  sequence.add(Integer. toString(i));
42            }
43            Selector selector = sequence.selector() ;
44             while(! selector.isEnd()){
45                 System. out.println( selector.currentObj());
46                  selector.next();
47            }
48      }
49 }
50  
  • 由此可见,内部类自动拥有对其外围类所有成员的访问权。这是如何做到的呢?当某个外围类的对象创建了一个内部类对象时,此内部类对象会捕获一个指向那个外围类的引用。
但是,可以看到:内部类的对象只能在与其外围类的对象相关联的情况下才能被创建。
 
使用.this和.new
  • 如果你想生成对外部类对象的引用,可以使用外部类的名字后面紧跟.this
 1 /**
 2  * 使用.this,获得外部类对象的引用
 3  * @author jing.ming
 4  *
 5  */
 6 public class DotThis {
 7  
 8      void f(){
 9            System. out.println( "DotThis.f()");
10      }
11      public class Inner{
12             public DotThis outer(){
13             return DotThis. this ;
14            }
15      }
16      public Inner inner(){
17             return new Inner();
18      }
19      
20      public static void main(String[] args){
21            DotThis dt = new DotThis() ;
22            DotThis.Inner dti = dt.inner();
23             dti.outer().f();
24      }
25 }
  • 创建内部类对象的引用,必须使用外部类的对象来创建该内部类对象,使用外部类.new语法
 1 /**
 2  * 创建内部类对象,使用.new语法
 3  * @author jing.ming
 4  *
 5  */
 6 public class DotNew {
 7  
 8      public class Inner{
 9            
10      }
11      public static void main(String[] args){
12            DotNew dn = new DotNew() ;
13            DotNew.Inner dti = dn. new Inner();
14      }
15 }
 
内部类与向上转型
当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地。可以很好地隐藏实现的细节,也避免了额外的扩展接口。
 1 /**
 2  * 内部类在接口中的重要应用
 3  *
 4  * @author jing.ming
 5  *
 6  */
 7 class Parcel4 {
 8      private class PContents implements Contents {
 9             private int i = 11;
10             @Override
11             public int value() {
12                  return i;
13            }
14      }
15      protected class PDestination implements Destination {
16             private String label;
17             private PDestination(String whereTo) {
18                  label = whereTo;
19            }
20 
21             @Override
22             public String readLable() {
23                  return label;
24            }
25      }
26      public Destination destination(String s) {
27           return new PDestination( s);
28      }
29      public Contents contents() {
30             return new PContents();
31      }
32 }
33  
34 public class TestParcel1 {
35      public static void main(String[] args) {
36            Parcel4 p = new Parcel4();
37            Contents c = p.contents();
38            Destination d = p.destination( "ShiYan");
39      }
40 }
内部类PContent是private的,所以除了Parcel4,没有人能访问它。
PDestination 是protected,所以只有Parcel4及其子类,还有与Parcel4同一个包中的类可以访问。
在方法和作用域内的内部类
这么做的理由:
  1. 如前所示,你实现了某类型的接口,于是可以创建并返回对其的引用。
  2. 你要创建一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的。
  • 方法的作用域内的类,称作局部内部类。
 1 /**
 2  * 局部内部类
 3  *
 4  * @author jing.ming
 5  *
 6  */
 7 public class Parcel5 {
 8      public Destination destination(String s) {
 9             class PDestination implements Destination {
10                  private String label;
11                  private PDestination(String whereTo) {
12                       label = whereTo;
13                 }
14                  @Override
15                  public String readLable() {
16                       return label;
17                 }
18            }
19             return new PDestination( s);
20      }
21      public static void main(String[] args) {
22            Parcel5 p = new Parcel5();
23            Destination d = p.destination( "ShiYan");
24      }
25 }
  • 下面的例子展示了如何在任意的作用域内嵌入一个内部类。
 1 /**
 2  * 在作用域内嵌入内部类
 3  * @author jing.ming
 4  *
 5  */
 6 public class Parcel6 {
 7      private void internalTracking( boolean b){
 8             if( b){
 9                  class TrackingSlip{
10                       private String id ;
11                      TrackingSlip(String s){
12                             id = s ;
13                      }
14                      String getSlip(){
15                             return id ;
16                      }
17                 }
18                 TrackingSlip ts = new TrackingSlip( "slip") ;
19                 String s = ts.getSlip();
20            }
21             //can't use it here!out of scope
22             //TrackingSlip ts = new TrackingSlip("x") ;
23      }
24      public void track (){
25            internalTracking( true) ;
26      }
27      public static void main(String[] args) {
28            Parcel6 p = new Parcel6() ;
29             p. track();
30      }
31  
32 }
匿名内部类
  • 无参构造函数匿名内部类
 1 /**
 2  * 匿名内部类使用
 3  * @author jing.ming
 4  *
 5  */
 6 public class Parcel7 {
 7      public Contents contents(){
 8             return new Contents(){
 9                  private int i = 11 ;
10                  public int value(){
11                       return i ;
12                 }
13            };
14      }
15      public static void main(String[] args) {
16            Parcel7 p = new Parcel7();
17            Contents c = p.contents() ;
18      }
19 }
20 等价与下面的实现:
21 public class Parcel7b {
22      class MyContents implements Contents{
23             private int i = 11 ;
24             public int value(){
25                  return i ;
26            }
27      }
28      //Contents c  = new MyContents() ;
29      public Contents contents(){
30             return new MyContents() ;
31      }
32      public static void main(String[] args) {
33            Parcel7 p = new Parcel7();
34            Contents c = p.contents() ;
35  
36      }
37 }
38  
  • 带参构造器的匿名内部类
 1 public class Wrapping {
 2      private int i ;
 3      public Wrapping( int x){
 4             i = x ;
 5      }
 6      public int value(){
 7             return i ;
 8      }
 9 }
10 ////
11 public class Parcel8 {
12      public Wrapping wrapping( int x){
13             return new Wrapping( x){
14                  public int value(){
15                       return super.value()*47;
16                 }
17            };
18      }
19      public static void main(String[] args) {
20            Parcel8 p = new Parcel8() ;
21            Wrapping w = p.wrapping(10);
22      }
23 }
  • 通过实例初始化,为匿名内部类创建构造器效果
 1 package org.mj.InnerClasses;
 2 /** 
 3  * @author: jing.ming 
 4  * @version 创建时间:2015年10月24日 上午11:26:59 
 5  * 匿名类产生构造器效果
 6  */
 7 abstract class Base{
 8     public Base(int i){
 9         System.out.println("Base Contructor,i="+i);
10     }
11     public abstract  void f();
12 }
13 public class AnonymousConstructor {
14     public static Base getBase(int i){
15         return new Base(i){
16             {System.out.println("Inside instance initializer.") ;}
17             public void f(){
18                 System.out.println("In anonymous f().");
19             }
20         };
21     }
22     public static void main(String[] args){
23         Base base  = getBase(47) ;
24         base.f();
25     }
26 
27 }

console输出:

Base Contructor,i=47
Inside instance initializer.
In anonymous f().
在此例中,不要求变量i一定是finald的。因为i被传递给匿名类的基类的构造器,它并不会在匿名类内部被直接使用。

嵌套类
如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。这就通常称为嵌套类。
这意味着:
  1. 要创建嵌套类的对象,并不需要其外围类的对象。
  2. 不能从嵌套类的对象中访问非静态的外围类对象。
  • 从多层嵌套类中访问外部类的成员
 1 package org.mj.InnerClasses;
 2 /** 
 3  * @author: jing.ming 
 4  * @version 创建时间:2015年10月24日 上午11:56:11 
 5  * 从多层嵌套类中访问外部类的成员
 6  */
 7 class MNA{
 8     private void f(){}
 9     class A{
10         private void g(){}
11         public class B{
12             void h(){
13                 g();
14                 f();
15             }
16         }
17     }
18 }
19 public class MultiNestingAccess {
20 
21     public static void main(String[] args) {
22         MNA mna = new MNA() ;
23         MNA.A mnaa = mna.new A() ;
24         MNA.A.B mnaab = mnaa.new B() ;
25         mnaab.h();
26 
27     }
28 
29 }
  • 内部类实现多重继承
 1 interface A{}
 2 interface B{}
 3 class X implements A,B{}
 4 class Y implements A{
 5      B makeB(){
 6             return new B(){};
 7      }
 8 }
 9 public class MultiInterfaces {
10      static void takesA(A a){}
11      static void takesB(B b){}
12  
13      public static void main(String[] args) {
14            X x = new X() ;
15            Y y = new Y();
16  
17             takesA(x);
18             takesB(x);
19            
20             takesA(y);
21             takesB(y.makeB());
22      }
23 }

 上面2种实现多重继承的方式不同,但是也没什么区别。它们都能正常运作。但是,如果拥有的是抽象类或具体的类,而不是接口,那就只能使用内部类才能实现多重继承

 1 package org.mj.MultiInterface;
 2 /**
 3  * @author jing.ming
 4  */
 5 class D{}
 6 abstract class E{}
 7 class Z extends D{
 8     E makeE(){return new E(){};}
 9 }
10 public class MultiImplementation {
11 
12     static void takeD(D d){}
13     static void takeE(E e){}
14     
15     public static void main(String[] args) {
16         Z z = new Z() ;
17         takeD(z) ;
18         takeE(z.makeE()) ;
19     }
20 
21 }
闭包与回调
 1 package org.mj.callbackInnerclass;
 2 
 3 interface Incrementable{void increment();}
 4 class Callee1 implements Incrementable{
 5     private int i = 0 ;
 6     @Override
 7     public void increment() {
 8         i++;
 9         System.out.println("i="+i);
10     }    
11 }
12 class MyIncrement{
13     public void increment(){
14         System.out.println("Other operation.");
15     }
16     static void f(MyIncrement mi){
17         mi.increment();
18     }
19 }
20 
21 class Callee2 extends MyIncrement{
22     private int i = 0 ;
23     public void increment(){
24         super.increment();
25         i++ ;
26         System.out.println("i="+i);
27     }    
28     private class Closure implements Incrementable{
29         @Override
30         public void increment() {
31             Callee2.this.increment();    
32         }        
33     }
34     Incrementable getCallbackReference(){
35         return new Closure() ;
36     }
37 }
38 
39 class Caller{
40     private Incrementable callbackReference ;
41     Caller(Incrementable cbh){
42         callbackReference = cbh ;
43     }
44     void go(){
45         callbackReference.increment();
46     }
47 }
48 public class Callbacks {
49     public static void main(String[] args) {
50         Callee1 c1 = new Callee1() ;
51         Callee2 c2 = new Callee2() ;
52         MyIncrement.f(c2);
53         Caller caller1 = new Caller(c1) ;
54         Caller caller2 = new Caller(c2.getCallbackReference()) ;
55         caller1.go();
56         caller1.go();
57         caller2.go();
58         caller2.go();
59     }
60 
61 }

运行结果:

Other operation.
i=1
i=1
i=2
Other operation.
i=2
Other operation.
i=3

     这个例子进一步展示了外围内实现一个接口与内部类实现此接口之间的区别。就代码而言,Callee1是简单的解决方式。Callee2继承自Mycrement,后者已经有了一个不同的increment()方法,并且与Incrementable接口期望的increment()方法完全不相干。所以如果Callee2继承了MyIncrement,就不能为了Incrementable的用途而覆盖increment()方法,于是只能使用内部类独立的实现Incrementable。还要注意,当建立了一个内部类时,并没有在外围类的接口中添加东西,也没有修改外围类的接口。

    内部类Closure实现了Incrementable,以提供一个返回Callee2的“钩子”(HOOK)——而且是一个安全的钩子,无论谁获得此Incrementable的引用,都只能调用increment(),除此之外没有其他功能(不像指针,允许你做很多事情)。

   回调的价值在于它的灵活性——可以在运行时动态地决定需要调用什么方法。这样做的好处在GUI功能的实现中得到很好的体现。

原文地址:https://www.cnblogs.com/jsStudyjj/p/4905850.html