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

Java学习:内部类,闭包与回调

2014年09月05日 ⁄ 综合 ⁄ 共 4762字 ⁄ 字号 评论关闭

  把一个类放在另一个类内部定义,这个定义在其他类内部的类称为内部类,当然也可以叫做嵌套类,这是面向对象中重要的一部分。内部类对于程序来说提供了更好的封装效果,外部类完全无法访问内部类的实现细节,因此可以将内部类隐藏在外部类中。而且由于内部类成员可以访问外部类的私有类成员,内部类可以看做是外部类的成员变量。当出现只需要使用一次的类时,可以使用更加灵活方便的匿名内部类。

        对于内部类,可以定义在外部类的任何位置,甚至可以定义在外部类的方法中(此时的内部类也可以叫做局部内部类),也可以定义在接口中,但是说接口中定义内部类的话默认使用public static进行修饰(接口中的内部类只能是静态内部类)。大部分的时候,内部类都被作为成员内部类定义,而不是当做局部内部类。成员内部类可以看做与外部类的属性、方法、构造器一样的类成员变量,但是局部内部类和匿名内部类不是类成员。

        通过内部类,可以实现闭包与回调。闭包是一种能被调用的对象,他保存了创建它的作用域信息。Java中没有显示的支持闭包功能,但是说非静态内部类可以记录外部类的详细信息,还保存了一个创建非内部静态类对象的引用,并且可以查看外部类的私有成员,因此可以完全可以把非静态内部类当成闭包。通过这种内部类可以很轻松的实现回调功能,回调就是说某个方法一旦获得了内部类对象引用和,就可以在合适的时候调用外部类实例的方法。

        1、静态内部类

        如果使用static关键字修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象,那么这个内部类就是所谓的静态内部类。

        静态内部类可以包含静态类成员,也可以包含非静态成员。静态内部类由于属于外部类,因此静态内部类无法访问外部类的实例成员,只能访问外部类的类变量。即便是静态内部类的实例方法也是不能访问外部类的实例成员,只能访问外部类的静态成员。

[java] view
plain
copy在CODE上查看代码片派生到我的代码片

  1. <span style="font-size:14px;">public class StaticInnerClassDemo {  
  2.       
  3.     private int key1 = 1;  
  4.     private static int key2 = 2;  
  5.       
  6.     static class Inner{  
  7.           
  8.         /** 
  9.          * 静态内部类的实例方法不能放外部类的实例成员是因为静态内 
  10.          * 部类本身不是寄存在外部类的实例对象中,也就是说当静态内 
  11.          * 部类实例存在是并不一定存在相应的外部引用。 
  12.          */  
  13.         public void showOuter()  
  14.         {  
  15.             //System.out.println(key1); 编译是根本无方通过check检测,报错  
  16.             System.out.println("key2 : " + key2); //静态内部类的非静态方法也只能访问外部类的静态成员遍历  
  17.         }  
  18.           
  19.     }  
  20.     public static void main(String[] args) {  
  21.       
  22.         System.out.println("key1 : " + new StaticInnerClassDemo().key1 );  
  23.         new StaticInnerClassDemo.Inner().showOuter();  
  24.   
  25.     }  
  26. }  
  27. </span>  


        静态内部类就是一个外部类的静态类成员,因此外部类的静态方法、静态初始化块中可以使用静态内部类来定义变量。
        2、非静态内部类
        非静态内部类可以看做是外部类的成员变量,与部类的属性、方法、构造器一样。与正常的普通类使用并无太大区别.

[java] view
plain
copy在CODE上查看代码片派生到我的代码片

  1. <span style="font-size:14px;">public class InnerClassDemo {  
  2.       
  3.     private int key = 1;  
  4.     public String valueString = "innerouter";  
  5.   
  6.     class Inner {  
  7.         public void show()  
  8.         {  
  9.             System.out.println("private key : " + key );  
  10.             System.out.println("public string : " + valueString);  
  11.         }  
  12.   
  13.     }  
  14.       
  15.     public void text()  
  16.     {  
  17.         Inner in = new Inner();  
  18.         in.show();  
  19.     }  
  20.   
  21.     public static void main(String[] args) {  
  22.   
  23.   
  24.         InnerClassDemo ic = new InnerClassDemo();  
  25.           
  26.         ic.text();  
  27.   
  28.     }  
  29.   
  30. }</span>  

        Ps:(如果出现外部类成员变量与内部类成员变量重名的情况,可以通过this,外部类名.this进行区分)
        非静态内部类成员由于可以看做外部类的成员变量,因此对于非静态内部类来说可以直接访问外部类的private成员,但是外部类不可以访问内部类的private成员变量,外部类实例如果想要访问静态内部类成员必须显式的创建非静态内部类对象来调用内部了类成员。
        需要注意的一点是非静态内部类里定义静态成员是非法的,无论是静态初始化块,还是静态成员变量、静态方法。
*****************************************************************************************************************************************************
        如果说需要在外部类以外的地方使用内部类,内部类不能定义为私有,而且此时的内部类名应该为OutClass.InnerClass。
        如果需要在外部类以外的地方创建非静态内部类的子类,则尤其要注意非静态内部类的构造器必须通过外部类对象进行调用。
                Out.In in = new Out().new In();
        当创建一个子类时,子类构造器总会调用父类构造器,因此在创建非静态内部类的子类时 ,必须保证子类构造器可以调用非静态内部类的构造器。但是说非静态内部类的子类不一定还是内部类,他完全可以是一个全新的外部类,这个子类需要保存一个其父类所在外部类的实例对象。也就是说存在一个内部类子类的实例,一定相应的存在一个与之对应的外部类实例。
******************************************************************************************************************************************************             3、局部内部类
        局部内部类尽在该方法中有效。他无法在外部类以外的地方有效,因此说局部内部类不存在静态一说。所有的局部内部类都不可以用static进行修饰。不仅如此,由于其作用与局限在方法内,因此其他程序单元永远无法访问其他方法的局部成员变量,所有的局部变量都是封闭的,不能使用访问控制符进行修饰。

[java] view
plain
copy在CODE上查看代码片派生到我的代码片

  1. <span style="font-size:14px;">public class MethodInnerClassDemo {  
  2.   
  3.     public static void main(String[] args) {  
  4.         class Inner1 //局部内部类  
  5.         {  
  6.             int key;  
  7.         }  
  8.         //局部内部类的继承  
  9.         class Inner2 extends Inner1  
  10.         {  
  11.             String value;  
  12.         }  
  13.   
  14.         Inner2 in = new Inner2();  
  15.           
  16.         in.key = 1;  
  17.         in.value = "one";  
  18.       
  19.         System.out.println(in.value + " : " + in.key );  
  20.     }  
  21. }  
  22. </span>  

        需要补充的是一个类中不允许和出现两个同名的成员内部类,但是允许有同名的局部内部类。
        4、匿名内部类
        匿名内部类充分体现了Java语言的灵活性,通过使用匿名内部类可以将只使用一次的类直接创建。匿名内部类的视线必须继承一个父类,或者说实现一个接口,但是说最多实现一个父类或者一个接口。
        匿名内部类不允许是抽象类,因为说定义匿名内部类时会立即创建匿名内部类的实例对象。而且匿名内部类不能定义构造器,因为它本身就不存在类名,不过可以定义实例初始化块,通过初始化块实现构造器对的功能。

[java] view
plain
copy在CODE上查看代码片派生到我的代码片

  1. <span style="font-size:14px;">interface product  
  2. {  
  3.     public void show();  
  4. }  
  5.   
  6. public class NoNameClassDemo {  
  7.       
  8.     public void text( product  p )  
  9.     {  
  10.         p.show();  
  11.     }  
  12.       
  13.   
  14.     public static void main(String[] args) {  
  15.   
  16.         NoNameClassDemo nn = new NoNameClassDemo();  
  17.           
  18.         nn.text(new product(){  
  19.             public void show() {  
  20.                 System.out.println("匿名内部类");  
  21.             }  
  22.         });  
  23.   
  24.     }  
  25. }  
  26. </span>  

        5、闭包与回调

        闭包是一种能被调用的对象,他保存了创建它的作用域信息。Java中没有显示的支持闭包功能,但是说非静态内部类可以记录外部类的详细信息,还保存了一个创建非内部静态类对象的引用,并且可以查看外部类的私有成员,因此可以完全可以把非静态内部类当成闭包。通过这种内部类可以很轻松的实现回调功能,回调就是说某个方法一旦获得了内部类对象引用和,就可以在合适的时候调用外部类实例的方法。

        这样让编程更加灵活。

【上篇】
【下篇】

抱歉!评论已关闭.