Java内部类小结

内部类:通俗的说就是定义在另一个类中的类,通过内部类,可以做到代码隐藏,内部类也可以和与外围类通信,有时,它可以让代码更优雅而清晰,本质作用:多重继承,信息隐藏,闭包回调,更加灵活适合应用控制框架;

心得:
1. 如果一个类实现了多个接口,不同的功能,那么通过内部类闭包的方式,可以返回给client不同接口的闭包,这样不同的client可以只获取对应功能的部分,这是一种安全的调用方式;

使用接口的方式:
a. 单一类;
b. 内部类;

内部的分类:
静态内部类;
非静态内部类;
匿名内部类;
局部内部类;


1. 内部类与外围类的关系

从这个例子谈起

1.1 内部来的代码隐藏作用

public  class  Parcel1 {
         class  Contents {
                private  int  i  = 11;
                public  int  value() {
                       return  1;
              }
       }
         class  Destination {
                private  String  label  ;
              Destination(String whereTo) {
                       label  = whereTo;
              }
              String readLabel() {  return  label  ;}
       }
       //在外部类的非静态方法中就可以“正常”地使用
         public  void  ship(String dest) {
              Contents c =  new  Contents();
              Destination d =  new  Destination(dest);
              System.  out .println(d.readLabel());
       }
         public  static  void  main(String args[]) {
              Parcel1 p =  new  Parcel1();
              p.ship(  "home" );
               //由于内部类隐藏代码的机制,你只能通过外部类的对象来创建内部类对象,除非加上static关键字
              Parcel1.Contents c p.new Contents();
       }
}

这说明,(非static的)内部类的生命周期存在于外部类之内,要想在外部非静态方法外使用当然要延长其生命周期,把内部类变成static的;
变成嵌套类;

非静态内部类
结论:
a. 生命周期:依赖与外部类;
b. 访问权限:内部类对象拥有外部类所有元素的访问权;

2. 访问外围类

内部类可以直接访问外围类的所有成员,在其中实际上有一个Outter.this到外围类的引用;

使用.this和.new操作:
通过Outter.this可以在内部类获得外围类对象实例;
创建内部类:Outter outter = outter.new Inner();

3. 内部类与向上转型

可以通过在将外围类设置成private或protected,并通过create()方法,在其他地方创建或获得内部类实例,但是需要一个接口或者基类来取得引用;

讨论下列情况:
public  class  UseInner {
         protected  class  II  implements  InnerInterface {
                private  int  i  = 11;
              
                public  class  A {
                       public  class  B {
                             public  class  C {
                                  
                           }
                     }
              }
              
                public  class  D {
                     
              }

                public  II() {  //这是必须的
                       //  TODO  Auto-generated constructor stub
              }

                @Override
                public  String test() {
                       //  TODO  Auto-generated method stub
                       return  String.valueOf(  i );
              }
       }

         public  static  void  main(String[] args) {
                //  TODO  Auto-generated method stub
              
       }

}

第三方使用者:
public  class  InnerITest  extends  UseInner {
         public  InnerInterface getII() {
                return  new  InnerITest.II();
       }

         public  static  void  main(String[] args) {
                //  TODO  Auto-generated method stub

       }

}

结论:即使内部类被声明为protected,在外围类的子类中如果要通过构造器创建其protected内部类,也需要该内部类有public构造器;如果该内部类被声明private的话,即使是外围类的子类也无法直接使用到内部类的Class

Constructor[] cs = II.  class .getConstructors();
              
for  (Constructor c : cs) {
     System.  out  .println(c.getName() +  "_"  + (c.getModifiers() == Modifier. PUBLIC  ));
}
getConstructors():只能获取到public构造器;

4. 内部类可以存在在哪里(这里作用域是其存在意义的标准)

4.1 方法和作用域内的内部类

4.2 匿名内部类(和向上转型紧密相关)


a. 需要注意:匿名内部类是继承了某个类,那么就不能直接使用父类的private域和方法;

b. 匿名内部类传参数:——需要基类有相应构造器;

c. 使用外围类的成员,可以直接使用,作用域局部变量需要final声明——作用域的限制;
你可能会想到容器为什么可以不用限制放入final对象实例呢?因为放入容器,实际上容器会创建一个指向实际对象的引用,这个引用是容器自己维护的,这个变量引用的作用域是在容器自身内的;但是内部类传入局部变量的话,这个变量引用什么对象并不是只受内部类控制,所以是不行的;

d. 匿名类的限制:一次只能实现或者继续一个接口或基类;

5. 工厂方法和内部类

interface  Service {
         void  method1();
         void  method2();
}

interface  ServiceFactory {
       Service create();
}

class  ServiceEx  implements  Service {

         @Override
         public  void  method1() {
                //  TODO  Auto-generated method stub
              
       }

         @Override
         public  void  method2() {
                //  TODO  Auto-generated method stub
              
       }
       
       ServiceFactory getFactory() {
                return  new  ServiceFactory() {

                       @Override
                       public  Service create() {
                             //  TODO  Auto-generated method stub
                             return  new  ServiceEx();
                     }
                     
              };
       }
}

public  class  FactoryInner {

         public  static  void  main(String[] args) {
                //  TODO  Auto-generated method stub

       }

}

总结:优先使用类而不是接口,如果你的设计中需要某个接口,必须彻底了解它!!!

6. 嵌套类

static 内部类:结构嵌套,互相独立;
在接口中可以定义嵌套类

7. 为什么需要内部类

a. 内部类是某种进入外围类的的窗口;
b. 更加灵活的多重继承,尤其是在要继承的接口和类有重叠的情况下(如方法签名相同);

7.1 闭包和回调(closure)

闭包使用的方式:
a. 指针;
b. 接口;

闭包:一个可调用的对象(内部类),它记录一些信息,这些信息来自于创建它的作用域(外围类);
内部类:面向对象(外围类对象)的闭包,它拥有一个指向外围类对象的引用:Outter.this;

回调:实现调用者和被调用者的分离,调用者不需要具体的被调用者(指针/接口),在运行时决定要调用什么方法,更加灵活;

7.2 内部类与控制框架

应用程序框架(application framework):我的理解就是用来解决一个主题问题的一组程序集合。设计应用程序框架,需要组件化来构成框架的各个部分,那么可能需要一个类继承和实现多个已有组件以及一个或多个可覆盖的方法,”将变化的和不变的事物分开“,典型运用模块方法,像Anroid中的activity等GUI中回调机制,大量运用了这个思想;

控制框架:用来解决 响应事件的需求;
书上给出了一个控制框架的例子,使用一个Controlls对象,维护一组Event时间,检查状态并执行,每个event都有自己ready()和action()来决定自己的行为;最后我们可以通过向controlls中放入不同的event来决定我们想要的东西是什么;

8. 内部类的继承

必须要让继承的类,和外部类连接起来
class  WithInner {
         class  Inner {
                   
       }
}

public  class  InheritInner  extends  WithInner.Inner {
       InheritInner(WithInner wi) {
              wi.  super (); //这一步必须的
       }

         public  static  void  main(String[] args) {
              
       }
}

9. 内部类可以被覆盖吗:不可以,在继承的类中重写内部类(类名一样)和基类的内部类没有关系,两者的命名空间根本不一样

如果要继承可以向这样:
public  class  BigEgg  extends  Egg {
         class  Yolk  extends  Egg.Yolk {
                public  Yolk() {
                     System.  out .println( "create BigEgg.Yolk"  );
              }
                @ Override
                public  void  f() {
                     System.  out .println( "BigEgg.f"  );
              }
       }
         public  BigEgg() {
              System.  out .println( "BigEgg"  );
                this . y  =  new  Yolk();
       }
         public  static  void  main(String[] args) {
              Egg e =  new  BigEgg();
       }
}
//Output:
Egg
create Egg.Yolk
BigEgg
create Egg.Yolk
create BigEgg.Yolk
分别继承基类及其外部类:从输出结果我们可以看到都是先执行基类的构造器在执行导出类的,内部类也一样;


10. 局部内部类

局部内部类和匿名内部类之间的区别:你可以在局部(如方法内)创建多个局部内部类实例,但是后者只能用于实例初始化。

你可能感兴趣的:(Java内部类小结)