你的位置:首页 > Java教程

[Java教程]Java内部类学习笔记


20160923

  • 定义:将一个类的定义放在另一个类的内部;
  • 从外部类的非静态方法之外,创建某个内部类的对象:OutClassName.InnerClassName;
  • 内部类拥有所有其外部类的成员的访问权;
  • 内部类中生成外部类对象的引用,可以使用OutClassName.this;
 1 public class DoThis { 2   void f(){System.out.println("DoThis.f()");} 3   public class Inner{ 4     public DoThis getOuter(){ 5       return DoThis.this; 6     } 7   } 8   public Inner getInner(){ 9     return new Inner();10   }11   public static void main(String[] args) {12     DoThis dThis = new DoThis();13     DoThis.Inner dThisInner = dThis.getInner();14     dThisInner.getOuter().f();15   }16 }

  • 创建内部类的对象,必须使用外部类对象的引用;
1 public class DoNew {2   public class Inner{};3   public static void main(String[] args) {4     DoNew doNew = new DoNew();5     DoNew.Inner dInner = doNew.new Inner();6   }7 }

  • 创建嵌套类(静态内部类),不需要外部类对象的引用;
  • private修饰的内部类,只能在其外部类内部访问;protected修饰的内部类,只有其外部类、其外部类的子类、其外部类同一个包中的其他类可以访问;
 1 class Parcel4{ 2   private class PContents implements Contents { 3     private int i = 11; 4     @Override 5     public int value() { return i; } 6   } 7   protected class PDestination implements Destination { 8     private String label; 9     private PDestination(String whereTo) { label = whereTo; }10     @Override11     public String readLabel() { return label; }12   }13   public Destination destination(String s){ return new PDestination(s); }14   public Contents contents(){ return new PContents(); }15   Parcel4.PContents t;//PContents是private,只能在Parcel4内部访问16 }17 public class TestParcel {18   public static void main(String[] args) {19     Parcel4 p = new Parcel4();20     Contents contents = p.contents();21     Destination destination = p.destination("Tasmania");22     //Parcel4.PContents pc = p.new PContents();//PContents是private,只能在Parcel4内部访问,此处报错23   }24 }

  • 复杂的内部类:在方法或作用域内定义内部类,理由如下:
  1. 实现了某个类型的接口,可以创建并返回对接口的引用
  2. 需解决复杂的问题,想创建一个类辅助实现解决方案,但不希望这个类被公用
  • 举例

    1、一个定义在方法中的类

 1 public class Parcel5 { 2   public Destination destination(String s){ 3     class PDestination implements Destination{ 4       private String label; 5       private PDestination(String whereTo){ 6         label = whereTo; 7       } 8       @Override 9       public String readLabel() { return label; }10     }11     return new PDestination(s);12   }13   public static void main(String[] args) {14     Parcel5 p = new Parcel5();15     Destination destination = p.destination("Tasmania");16   }17 }

    2、一个定义在作用域中的类,作用域在方法的内部

 1 public class Parcel6 { 2   private void internalTracking(boolean b) { 3     if (b){ 4       class TrackingSlip { 5         private String id; 6         public TrackingSlip(String s) { 7           id = s; 8         } 9         String getSlip(){ return id;}10       }11       TrackingSlip ts = new TrackingSlip("slip");12       String s = ts.getSlip();13     }14     //Can't use it here!Out of scope:15     //TrackingSlip ts = new TrackingSlip("x");16   }17   public void track(){internalTracking(true);}18   public static void main(String[] args) {19     Parcel6 p = new Parcel6();20     p.track();21   }22 }

    3、一个实现了接口的匿名类

    4、一个匿名类,扩展了有非默认构造器的类

    5、一个匿名类,执行字段初始化

    6、一个匿名类,通过实例初始化实现构造(匿名类没有构造器)

  • 传递给匿名内部类的参数,并且在匿名内部类中使用,该参数须定义为final;
  • 匿名内部类可扩展类,也可以实现接口,但不能同时;如果实现接口,只能实现一个接口;
  • 《Java编程思想》199页,10.6.1再访工厂方法,使用匿名内部类的例子,非常好;
  • 嵌套类:static修饰的内部类,无法访问非静态的外部类对象
  • 嵌套类可以作为接口的一部分,甚至实现外部接口
  •  1 public interface ClassInInterface { 2   void howdy(); 3   class Test implements ClassInInterface{ 4     @Override 5     public void howdy() { System.out.println("Howdy"); } 6     public static void main(String[] args){ 7       new Test().howdy(); 8     } 9   }10 }

  • 内部类能够多层嵌套,并且能够透明的访问所有它嵌入的外部类的成员
  •  1 class A{ 2   private void f(){} 3   class B { 4     private void g(){} 5     public class C { 6       void h() { 7         g(); 8         f(); 9       }10     }11   }12 }13 public class MultiNestingAccess {14   public static void main(String[] args) {15     A a = new A();16     A.B ab = a.new B();17     A.B.C abc =ab.new C();18     abc.h();19   }20 }

  • 为什么需要内部类?
    • 《Java编程思想》204页解释为:每个内部类都能独立的继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响;
    • 简单讲就是,内部类实现接口、继承某个类,比外部类实现接口少了许多顾虑,外部类实现接口需要考虑全面,在其他地方是否有影响;
    • 内部类可以继承多个具体类或抽象类,与接口配合,使“多重继承”的解决方案变得完美;
    • 内部类可以有多个实例,每个实例都有自己的状态信息,并且与外部类对象相互独立;
    • 在单个外部类中,可以使多个内部类以不同的方式实现同一个接口,或继承同一个类;
    • 内部类对象的创建,并不依赖于外部类对象的创建
    • 内部类没有“is-a”关系,内部类是独立的实体
  • 闭包,记录了创建闭包的作用域的一些信息,使得闭包可调用其外部作用域数据;内部类就是面向对象的闭包;
  • 回调,
  • 通过内部类提供闭包功能举例:
  •  1 package com.helei.innerclasses; 2 interface Incrementable { 3   void increment(); 4 } 5 class Callee1 implements Incrementable { 6   private int i = 0; 7   @Override 8   public void increment() { 9     i++;10     System.out.println(i);;11   }12 }13 class MyIncrement {14   public void increment() { System.out.println("Other operation");}15   static void f(MyIncrement mi) {mi.increment();}16 }17 class Callee2 extends MyIncrement {18   private int i = 0;19   public void increment() {20     super.increment();21     i++;22     System.out.println(i);23   }24   private class Closure implements Incrementable {25     public void increment() {26       Callee2.this.increment();27     }28   }29   Incrementable getCallbackReference() {30     return new Closure();31   }32 }33 class Caller {34   private Incrementable callbackReference;35   Caller(Incrementable cbh){callbackReference = cbh;}36   void go() {callbackReference.increment();}37 }38 public class Callbacks {39   public static void main(String[] args) {40     Callee1 c1 = new Callee1();41     Callee2 c2 = new Callee2();42     MyIncrement.f(c2);43     Caller caller1 = new Caller(c1);44     Caller caller2 = new Caller(c2.getCallbackReference());45     caller1.go();46     caller1.go();47     caller2.go();48     caller2.go();49   }50 }

  • 看了好几遍才梳通了以上流程,最好能够敲一遍,通过debug调试过一遍
  • 内部类与控制框架
  • 内部类的继承
  • 内部类覆盖,无效;可以显式继承某内部类;
  • 局部内部类,与匿名内部类的区别