第十章:内部类

第十章:内部类

1、内部类表面上看就是一种代码隐藏机制

2、其实内部类能与外部类通信,并且含有一个外部类的引用,所以能访问外部类所有的成员,包括private

3、内部类解决一部分的语言设计问题;类具有单继承的局限性,接口可以多继承、多实现,当然类也能多重继承(A继承B,B继承C);

然而多个内部类可以继承或实现多个接口,保证了语言的完整性。

一、链接外部类

内部类有权访问内部类所有成员,包括私有化成员,因为内部类存有外部类的引用

public class Parcel2 {
    
    
  private int i = 2;
  private void println(){
    
    System.out.println(i);}
  class Contents {
    
    
    private int i = 11;
    public int value() {
    
     return i; }
  }
  class Destination {
    
    
    private String label;
    Destination(String whereTo) {
    
    
      label = whereTo;
    }
    String readLabel() {
    
    
      println();//访问外部类私有化成员方法
      return label+"_访问外部类私有化成员变量i="+i; }
  }
  public Destination to(String s) {
    
    
    return new Destination(s);
  }
  public Contents contents() {
    
    
    return new Contents();
  }
  public void ship(String dest) {
    
    
    Contents c = contents();
    Destination d = to(dest);
    System.out.println(d.readLabel());
  }
  public static void main(String[] args) {
    
    
    Parcel2 p = new Parcel2();
    p.ship("Tasmania");
    Parcel2 q = new Parcel2();
    // Defining references to inner classes:
    Parcel2.Contents c = q.contents();
    Destination d = q.to("Borneo");
    System.out.println(c.i);//本类中,允许访问内部类私有化成员
  }
} /* Output:
2
Tasmania_访问外部类私有化成员i=2
11
*///:~

二、非静态成员位置内部类

1、用 OutClass.InnerClass 表示内部类类型,在1.8后直接可以使用InnerClass表示内部类类型。

2、创建内部类,先要创建外部类,利用外部类的引用创建内部类,例如:

OuterClass out = new OutClass();

OutClass.InnerClass = out.new InnerClass();

3、非静态成员内部了理解为成员位置的非静态方法,所以要使用内部类必须先创建外部类的引用。

public class Parcel2 {
    
    
  class Contents {
    
    
    private int i = 11;
    public int value() {
    
     return i; }
  }
  class Destination {
    
    
    private String label;
    Destination(String whereTo) {
    
    
      label = whereTo;
    }
    String readLabel() {
    
     return label; }
  }
  public Destination to(String s) {
    
    
    return new Destination(s);
  }
  public Contents contents() {
    
    
    return new Contents();
  }
  public void ship(String dest) {
    
    
    Contents c = contents();
    Destination d = to(dest);
    System.out.println(d.readLabel());
  }
  public static void main(String[] args) {
    
    
    Parcel2 p = new Parcel2();
    p.ship("Tasmania");
    Parcel2 q = new Parcel2();
    // Defining references to inner classes:
    Contents c = q.contents(); //也可以Parcel2.Contents c = q.contents();或者q.new Contents();
    Destination d = q.to("Borneo");
  }
} /* Output:
Tasmania
*///:~

三、静态成员位置内部类(也称 嵌套类)

1、静态内部类不存在外部类的引用,随类的加载而初始化,所以不能直接访问外部类的非静态成员。

2、返回值类型直接使用 InnerClass类型

3、静态成员内部类会编译OuterClass$InnerClass.class文件。

public interface ClassInInterface {
    
    
  void howdy();
  class Test implements ClassInInterface {
    
    //默认public static修饰
    public void howdy() {
    
    
      System.out.println("Howdy!");
    }
    public static void main(String[] args) {
    
    
      new Test().howdy();
    }
  }
} /* Output:
Howdy!
*///:~

作用:静态内部类做测试使用,不会写太多文件,也不用从新编译代码

public class TestBed {
    
    
  public void f() {
    
     System.out.println("f()"); }
  public static class Tester {
    
    
    public static void main(String[] args) {
    
    
      TestBed t = new TestBed();
      t.f();
    }
  }
} /* Output:
f()
*///:~

四、使用this和new

OuterClass.this用在内部类中表示外部类的引用,从而调用外部类的成员。

public class DotThis {
    
    
  void f() {
    
     System.out.println("DotThis.f()"); }
  public class Inner {
    
    
    public DotThis outer() {
    
    
      // 这里使用外部类.this表示使用外部类对象的引用
      return DotThis.this;
    }
  }
  public Inner inner() {
    
     return new Inner(); }
  public static void main(String[] args) {
    
    
    DotThis dt = new DotThis();
    Inner dti = dt.inner();
//  Inner dti = dt.new Inner(); 这种写法和上面一样有效,可以非静态成员内部了理解为成员位置的非静态方法
    dti.outer().f();
  }
} /* Output:
DotThis.f()
*///:~

五、内部类向上转型

1、内部类被private修饰表示私有化成员,只能本类中访问;这样具有隐蔽性

2、被protected修饰的内部类只能本包中或子类访问。

3、内部类提升为基类型指向子类型,调用子类覆盖的方法。

package innerclasses;

class Parcel4 {
    
    
  private class PContents implements Contents {
    
    
    private int i = 11;
    public int value() {
    
     return i; }
  }
  protected class PDestination implements Destination {
    
    
    private String label;
    private PDestination(String whereTo) {
    
    
      label = whereTo;
    }
    public String readLabel() {
    
     return label; }
  }
  public Destination destination(String s) {
    
    
    return new PDestination(s);
  }
  public Contents contents() {
    
    
    return new PContents();
  }
}

public class TestParcel {
    
    
  public static void main(String[] args) {
    
    
    Parcel4 p = new Parcel4();
    Contents c = p.contents();
    //System.out.println(c.i); 这种是不允许的,因为成员已经是私有化的
    Destination d = p.destination("Tasmania");
    // 如下代码是错误的,因为该成员被修饰了private、protected,类外无法被访问 
    // Parcel4.PContents pc = p.new PContents();
//    Parcel4.PDestination = p.new PDestination();
  }
} ///:~

六、局部内部类(方法和作用域中的内部类)

1、为了解决某些问题,又不想这个类被公用

2、局部内部类它的生命周期随方法或者作用域一样,方法执行完,生命周期就结束。

方法中的内部类:

public class Parcel5 {
    
    
  public Destination destination(String s) {
    
    
    class PDestination implements Destination {
    
    
      private String label;
      private PDestination(String whereTo) {
    
    
        label = whereTo;
      }
      public String readLabel() {
    
     return label; }
    }
    return new PDestination(s);//返回Destination引用指向PDestination子类
  }
  public static void main(String[] args) {
    
    
    Parcel5 p = new Parcel5();
    Destination d = p.destination("Tasmania");
  }
} ///:~

作用域中的内部类:

public class Parcel6 {
    
    
  private void internalTracking(boolean b) {
    
    
    if(b) {
    
    
      class TrackingSlip {
    
    
        private String id;
        TrackingSlip(String s) {
    
    
          id = s;
        }
        String getSlip() {
    
     return id; }
      }
      TrackingSlip ts = new TrackingSlip("slip_作用域中内部类");
      String s = ts.getSlip();
      System.out.println(s);
    }
    // 超出作用域,无效
    //! TrackingSlip ts = new TrackingSlip("x");
  }    
  public void track() {
    
     internalTracking(true); }
  public static void main(String[] args) {
    
    
    Parcel6 p = new Parcel6();
    p.track();
  }
} /* Output:
slip_作用域中内部类
*///:~

七、匿名内部类

默认构造的匿名内部类:

public class Parcel7 {
    
    
  public Contents contents() {
    
    
    return new Contents() {
    
     // 返回Contents的子类型
      private int i = 11;
      public int value() {
    
     return i; }
    }; // 分号结尾
  }
  public static void main(String[] args) {
    
    
    Parcel7 p = new Parcel7();
    Contents c = p.contents();
  }
}

带参数构造的匿名内部类:

1、匿名内部类想做一些类似构造器的效果:如下使用代码块,初始化时调用,就有效果了。

2、匿名内部类没有直接使用一个外部定义的对象,所以不要使用final修饰;当然jdk1.8后可以不使用final修饰也行。

public interface Destination {
    
    
  String readLabel();
}

abstract class Base {
    
    
  public Base(int i) {
    
     //没有使用final修饰
    print("Base constructor, i = " + i);
  }
  public abstract void f();
}	

public class Parcel10 {
    
    
  //由于外部定义的变量被匿名内部类的基类使用,而没有直接使用,所以不用使用final修饰
  public static Base getBase(int i) {
    
    
    return new Base(i) {
    
      // 带参数的构造器
      {
    
     print("Inside instance initializer"); }//代码块
      public void f() {
    
    
        print("In anonymous f()");
      }
    };
  }
  // 匿名内部类需要直接使用了一个外部定义的局部变量,需加final修饰
  public Destination destination(final String dest, final float price) {
    
    
    return new Destination() {
    
    
      private int cost;
      // Instance initialization for each object:
      {
    
    
        cost = Math.round(price);
        if(cost > 100)
          System.out.println("Over budget!"+cost);
      }
      private String label = dest;
      public String readLabel() {
    
     return label; }
    };
  }    
  public static void main(String[] args) {
    
    
    Parcel10 p = new Parcel10();
    Destination d = p.destination("Tasmania", 101.395F);
    System.out.println(d.readLabel());
    System.out.println("======静态内部类=======");
    Base base = getBase(47);
    base.f();
  }
} /* Output:
Over budget!
Tasmania
======静态内部类=======
Base constructor, i = 47
Inside instance initializer
In anonymous f()
*///:~
工厂方法:
interface Game {
    
     boolean move(); }
interface GameFactory {
    
     Game getGame(); }

class Checkers implements Game {
    
    
  private Checkers() {
    
    }
  private int moves = 0;
  private static final int MOVES = 3;
  public boolean move() {
    
    
    print("Checkers move " + moves);
    return ++moves != MOVES;
  }
  public static GameFactory factory = new GameFactory() {
    
    
    public Game getGame() {
    
     return new Checkers(); }
  };
}    

public class Games {
    
    
  public static void playGame(GameFactory factory) {
    
    
    Game s = factory.getGame();
    while(s.move())
      ;
  }
  public static void main(String[] args) {
    
    
    playGame(Checkers.factory);
  }
} /* Output:
Checkers move 0
Checkers move 1
Checkers move 2
*///:~

八、为什么使用内部类

优点:

①多个内部类是可以继承多个类或抽象类,不管外部类是否继承该类

②解决设计问题,使得多重继承变的更加完整

interface U {
    
    
   void f();
   void g();
   String toString();
}

class A {
    
    
   U buildU() {
    
    
      return new U() {
    
    
         public void f() {
    
     System.out.println("f()"); }
         public void g() {
    
     System.out.println("g()"); }
         public String toString() {
    
     return "I'm a U"; }
      };
   }
}

class B {
    
    
   private U[] us;
   B(int i) {
    
    
      us = new U[i];
   }
   void addU(U u, int i) {
    
    
      us[i] = u;
   }
   void eraseU(int i) {
    
    
      us[i] = null;  
   }
   void testUs() {
    
    
      for(U u : us) {
    
    
         u.f();
         u.g();
         u.toString();
      }     
   }
   void showUs() {
    
    
      for(U u : us) {
    
     
         if(u != null) System.out.println(u.toString());
         else System.out.println("I'm null");
      }
   }
}

public class Ex23 {
    
    
   public static void main(String[] args) {
    
    
      A a0 = new A();
      A a1 = new A();
      A a2 = new A();
      B b = new B(3);
      b.addU(a0.buildU(), 0);
      b.addU(a1.buildU(), 1);
      b.addU(a2.buildU(), 2);
      b.showUs();
      b.testUs();
      b.eraseU(0);
      b.eraseU(1);
      b.showUs();
   }
}
闭包:

​ 内部类是一个闭包,有自己的成员作用域,也有外部类的引用,可以操作外部类的成员(包括private修饰的)。

回调:

​ 运行时才知道调用的方法,调用后返回一些信息(比如dubbo,这样就知道是否执行成功)

interface Incrementable {
    
    
  void increment();
}

// Very simple to just implement the interface:
class Callee1 implements Incrementable {
    
    
  private int i = 0;
  public void increment() {
    
    
    i++;
    print(i);
  }
}  

class MyIncrement {
    
    
  public void increment() {
    
     print("Other operation"); }
  static void f(MyIncrement mi) {
    
     mi.increment(); }
}  

// If your class must implement increment() in
// some other way, you must use an inner class:
class Callee2 extends MyIncrement {
    
    
  private int i = 0;
  public void increment() {
    
    
    super.increment();
    i++;
    print(i);
  }
  private class Closure implements Incrementable {
    
    
    public void increment() {
    
    
		//调用了外部类的increment方法,不然就死循环
      Callee2.this.increment();
    }
  }
  Incrementable getCallbackReference() {
    
     //回调方法返回引用
    return new Closure();
  }
}  

class Caller {
    
    
  private Incrementable callbackReference;
  Caller(Incrementable cbh) {
    
     callbackReference = cbh; }
  void go() {
    
     callbackReference.increment(); } //回调方法,执行操作有输出
}

public class Callbacks {
    
    
  public static void main(String[] args) {
    
    
    Callee1 c1 = new Callee1();
    Callee2 c2 = new Callee2();
    MyIncrement.f(c2);
    Caller caller1 = new Caller(c1);
    Caller caller2 = new Caller(c2.getCallbackReference());
    caller1.go();
    caller1.go();
    caller2.go();
    caller2.go();
  }    
} /* Output:
Other operation
1
1
2
Other operation
2
Other operation
3
*///:~

九、继承内部类

1、继承非静态内部类,内部类构造器必须连接外部类的引用,这样只能先初始化外部类,才能初始化内部类。

2、静态内部类则不需要初始化外部类,随着类的加载而初始化。

class WithInner {
    
    
  private String s = "_I'm ok";
  WithInner(){
    
    
    System.out.println("已初始化外部类"+s);
  }
  class Inner {
    
    
    Inner(){
    
    
      System.out.println("已初始化内部类"+s);
    }
  }
  static class Inner_01{
    
    
    Inner_01(){
    
    
      System.out.println("已初始化非私有化静态内部类");
    }
  }
  private static class Inner_02{
    
    
    Inner_02(){
    
    
      System.out.println("已初始化私有化静态内部类");
    }
  }
}

public class InheritInner extends WithInner.Inner {
    
    //继承非静态内部类
  //! InheritInner() {} // 编译失败
  InheritInner(WithInner wi) {
    
    
    wi.super();//外部类引用调用内部类的构造方法
  }
  public static void main(String[] args) {
    
    
    WithInner wi = new WithInner();
    InheritInner ii = new InheritInner(wi);
    new WithInner.Inner_01();
   // new WithInner.Inner_02(); 报错,私有化不能访问
  }
}  /* Output:
已初始化外部类_I'm ok
已初始化内部类_I'm ok
已初始化非私有化静态内部类 *///:~

十:内部类不可被覆盖

class Egg {
    
    
  private Yolk y;
  protected class Yolk {
    
    
    public Yolk() {
    
     print("Egg.Yolk()"); }
  }
  public Egg() {
    
    
    print("New Egg()");
    y = new Yolk();
  }
}  

public class BigEgg extends Egg {
    
    
  public class Yolk {
    
    
    public Yolk() {
    
     print("BigEgg.Yolk()"); }
  }
  public static void main(String[] args) {
    
    
    new BigEgg();
  }
} /* Output:
New Egg()
Egg.Yolk()
*///:~

如下继承内外部类提升类型调用:覆盖的内部类

class Egg2 {
    
    
  protected class Yolk {
    
    
    public Yolk() {
    
     print("Egg2.Yolk()"); }
    public void f() {
    
     print("Egg2.Yolk.f()");}
  }
  private Yolk y = new Yolk();
  public Egg2() {
    
     print("New Egg2()"); }
  public void insertYolk(Yolk yy) {
    
     y = yy; }
  public void g() {
    
     y.f(); }
}  

public class BigEgg2 extends Egg2 {
    
    
  public class Yolk extends Egg2.Yolk {
    
    
    public Yolk() {
    
     print("BigEgg2.Yolk()"); }
    public void f() {
    
     print("BigEgg2.Yolk.f()"); }
  }
  public BigEgg2() {
    
     insertYolk(new Yolk()); }
  public static void main(String[] args) {
    
    
    Egg2 e2 = new BigEgg2();
    e2.g();
  }
} /* Output:
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()
*///:~

猜你喜欢

转载自blog.csdn.net/jue6628/article/details/104484418