《java编程思想》学习笔记——内部类五

10.5 在方法和做用域内的内部类java

一、能够在一个方法里面或者任意的做用域内定义内部类。这么作有两个理由:设计模式

(1)实现某类型的接口,因而能够建立并返回对其的引用。闭包

(2)要解决一个复杂的问题,想建立一个类来辅助你的解决方案,可是又不但愿这个类是共工可用的。 如下是局部内部类:app

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);
    }

    public static void mian(String[] args)
    {
        Parcel5 p = new Parcel5();
        Destination d = p.destination("");
    }
}

二、如下的内部类TrackingSlip其实和其余的类一块儿编译过了。然而在定义TrackingSlip的做用域以外,它是不可用的,除此以外,它和普通的类同样。框架

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();
    }
    // Can't use it here! Out of scope:
    //! TrackingSlip ts = new TrackingSlip("x");
  }	
  public void track() { internalTracking(true); }
  public static void main(String[] args) {
    Parcel6 p = new Parcel6();
    p.track();
  }
}

10.6匿名内部类ide

一、使用默认构造器this

public class Parcel7 {
  public Contents contents() {
    return new Contents() {
      private int i = 11;
      public int value() { return i; }
    }; 
  }
  public static void main(String[] args) {
    Parcel7 p = new Parcel7();
    Contents c = p.contents();
    System.out.println(c.value());
  }
}

以上写法等价于如下写法:设计

public class Parcel7b {
  class MyContents implements Contents {
    private int i = 11;
    public int value() { return i; }
  }
  public Contents contents() { return new MyContents(); }
  public static void main(String[] args) {
    Parcel7b p = new Parcel7b();
    Contents c = p.contents();
    System.out.println(c.value());
  }
}

二、基类须要一个有参数的构造器code

public class Wrapping {
  private int i;
  public Wrapping(int x) { i = x; }
  public int value() { return i; }
} 
public class Parcel8 {
  public Wrapping wrapping(int x) {
    return new Wrapping(x) { 
      public int value() {
        return super.value() * 47;
      }
    }; 
  }
  public static void main(String[] args) {
    Parcel8 p = new Parcel8();
    Wrapping w = p.wrapping(10);
  }
}

三、若是定义一个匿名内部类,而且但愿它使用一个在其外部定义的对象,那么编译器会要求其参数时final的。如:对象

public class Parcel9 {
  public Destination destination(final String dest) {
    return new Destination() {
      private String label = dest;
      public String readLabel() { return label; }
    };
  }
  public static void main(String[] args) {
    Parcel9 p = new Parcel9();
    Destination d = p.destination("Tasmania");
  }
}

四、在匿名内部类中不可能有命名构造器(由于它根本没有名字),但经过实例初始化,就能达到为匿名内部类建立一个构造器的效果。如:

abstract class Base {
  public Base(int i) {
    System.out.print("Base constructor, i = " + i);
  }
  public abstract void f();
}	

public class AnonymousConstructor {
  public static Base getBase(int i) {
    return new Base(i) {
      {  System.out.print("Inside instance initializer"); }
      public void f() {
    	  System.out.print("In anonymous f()");
      }
    };
  }
  public static void main(String[] args) {
    Base base = getBase(47);
    base.f();
  }
}

此例中,不要求变量i必定是final的。由于i被传递给匿名类的基类的 构造器,它并不会在匿名内部被直接使用。

10.6.1再访工厂方法 一、例一:

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

interface ServiceFactory {
  Service getService();
}	

class Implementation1 implements Service {
  private Implementation1() {}
  public void method1() {System.out.println("Implementation1 method1");}
  public void method2() {System.out.println("Implementation1 method2");}
  public static ServiceFactory factory =
    new ServiceFactory() {
      public Service getService() {
        return new Implementation1();
      }
    };
}	

class Implementation2 implements Service {
  private Implementation2() {}
  public void method1() {System.out.println("Implementation2 method1");}
  public void method2() {System.out.println("Implementation2 method2");}
  public static ServiceFactory factory =
    new ServiceFactory() {
      public Service getService() {
        return new Implementation2();
      }
    };
}	

public class Factories {
  public static void serviceConsumer(ServiceFactory fact) {
    Service s = fact.getService();
    s.method1();
    s.method2();
  }
  public static void main(String[] args) {
    serviceConsumer(Implementation1.factory);
    // Implementations are completely interchangeable:
    serviceConsumer(Implementation2.factory);
  }
}

二、例二:

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() {
	  System.out.println("Checkers move " + moves);
    return ++moves != MOVES;
  }
  public static GameFactory factory = new GameFactory() {
    public Game getGame() { return new Checkers(); }
  };
}	

class Chess implements Game {
  private Chess() {}
  private int moves = 0;
  private static final int MOVES = 4;
  public boolean move() {
	  System.out.println("Chess move " + moves);
    return ++moves != MOVES;
  }
  public static GameFactory factory = new GameFactory() {
    public Game getGame() { return new Chess(); }
  };
}	

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);
    playGame(Chess.factory);
  }
}

10.7嵌套类

一、若是不须要内部类对象与其外围类对象之间有联系,那么能够将内部类声明为static.这一般陈伟嵌套类。

二、普通的内部类对象隐式的保存了一个引用,指向建立它的外围类对象。然而,当内部类 是static时,状况就以下了:

(1)要建立嵌套类的对象,并不须要其外围类的对象。

(2)不能从嵌套类的对象访问非静态的外围类对象。

三、普通内部类的字段与方法,只能放在类的外部层次上,因此普通的内部类不能有static数据和static字段,也不能包含嵌套类。可是嵌套类能够包含全部这些东西:

public class Parcel11 {
  private static class ParcelContents implements Contents {
    private int i = 11;
    public int value() { return i; }
  }
  protected static class ParcelDestination
  implements Destination {
    private String label;
    private ParcelDestination(String whereTo) {
      label = whereTo;
    }
    public String readLabel() { return label; }	
    // Nested classes can contain other static elements:
    public static void f() {}
    static int x = 10;
    static class AnotherLevel {
      public static void f() {}
      static int x = 10;
    }
  }
  public static Destination destination(String s) {
    return new ParcelDestination(s);
  }
  public static Contents contents() {
    return new ParcelContents();
  }
  public static void main(String[] args) {
    Contents c = contents();
    Destination d = destination("Tasmania");
  }
}

10.7.1接口内部的类 一、正常状况下,不能在接口内部放置任何代码,但嵌套能够做为接口的一部分。你放的接口的任何类都自动地是public和static的。

二、若是你想要建立某些公共代码,使得它们能够被某个接口的全部实现所公用,那么使用接口内部类的嵌套类会显得很方便。

10.7.2从多层嵌套类中访问外部类的成员

一、一个内部类被嵌套多少层不重要——它能透明地访问全部它所嵌入的外围类的全部成员。

class MNA {
  private void f() {}
  class A {
    private void g() {}
    public class B {
      void h() {
        g();
        f();
      }
    }
  }
}	

public class MultiNestingAccess {
  public static void main(String[] args) {
    MNA mna = new MNA();
    MNA.A mnaa = mna.new A();
    MNA.A.B mnaab = mnaa.new B();
    mnaab.h();
  }
}

10.8为何须要内部类

一、每一个内部类都能独地继承自一个(接口的)实现,因此无乱外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

二、内部类容许继承多个非接口类型。

interface A {}
interface B {}

class X implements A, B {}

class Y implements A {
  B makeB() {
    // Anonymous inner class:
    return new B() {};
  }
}

public class MultiInterfaces {
  static void takesA(A a) {}
  static void takesB(B b) {}
  public static void main(String[] args) {
    X x = new X();
    Y y = new Y();
    takesA(x);
    takesA(y);
    takesB(x);
    takesB(y.makeB());
  }
}

三、若是拥有的是抽象的类或具体的类,而不是接口,那就只能使用内部类才能实现多重继承。

class D {}
abstract class E {}

class Z extends D {
  E makeE() { return new E() {}; }
}

public class MultiImplementation {
  static void takesD(D d) {}
  static void takesE(E e) {}
  public static void main(String[] args) {
    Z z = new Z();
    takesD(z);
    takesE(z.makeE());
  }
}

四、若是使用内部类,还能够得到其余一些特性

(1)内部类可使用多个实例,每一个实例都有本身的状态信息,而且与其外围类对象的信息相互独立。

(2)在单个外围类中,均可以让多个内部类以不一样的方式实现同一个接口,或继承同一个类。

(3)建立内部类对象的时刻并不依赖于外围类对象的建立。

(4)内部类并无使人迷惑的“is-a”关系,它就是一个独立的实体。

10.8.1闭包与回调

一、内部类是面向对象的闭包,由于它不只包含外围类对象(建立内部类的做用域)的信息,还自动拥有一个指向此外围类对象的引用,在此做用域内,内部类有权操做全部的成员,包括private。

interface Incrementable {
  void increment();
}

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

class MyIncrement {
  public void increment() { System.out.println("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++;
    System.out.println(i);
}
  
private class Closure implements Incrementable {
    public void increment() {
      // Specify outer-class method, otherwise
      // you'd get an infinite recursion:
      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
*///:~

10.8.2内部类与控制框架

一、设计模式总将变化的事物与保持不变得事物分离开,在这个模式中,模板方法是保持不变的事物,而可覆盖的方法就是变化的事物。

10.9内部类的继承

一、那个指向外围类对象的“秘密”引用必须被初始化,而在导出中再也不存在可链接的默认的对象。

class WithInner {
  class Inner {}
}

public class InheritInner extends WithInner.Inner {
  //! InheritInner() {} // Won't compile
  InheritInner(WithInner wi) {
    wi.super();
  }
  public static void main(String[] args) {
    WithInner wi = new WithInner();
    InheritInner ii = new InheritInner(wi);
  }
}

10.10内部类能够被覆盖吗

一、当继承了某个外围类的时候,内部类并无发生什么特别神奇的变化。这两个内部类是彻底独立的实体,各自在本身的命名空间内。

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

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

class Egg2 {
  protected class Yolk {
    public Yolk() { System.out.println("Egg2.Yolk()"); }
    public void f() { System.out.println("Egg2.Yolk.f()");}
  }
  private Yolk y = new Yolk();
  public Egg2() { System.out.println("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() { System.out.println("BigEgg2.Yolk()"); }
    public void f() { System.out.println("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()
*///:~

10.11局部内部类

一、惟一的理由是,咱们须要一个命名的构造器,或是须要重载构造器,而匿名内部类只能用于实例初始化。因此使用局部类而不使用匿名内部类的另外一个理由是,须要不仅一个该内部类的对象。

interface Counter {
  int next();
}	

public class LocalInnerClass {
  private int count = 0;
  Counter getCounter(final String name) {
    // A local inner class:
    class LocalCounter implements Counter {
      public LocalCounter() {
        // Local inner class can have a constructor
    	  System.out.println("LocalCounter()");
      }
      public int next() {
    	  System.out.println(name); // Access local final
        return count++;
      }
    }
    return new LocalCounter();
  }	
  // The same thing with an anonymous inner class:
  Counter getCounter2(final String name) {
    return new Counter() {
      // Anonymous inner class cannot have a named
      // constructor, only an instance initializer:
      {
    	  System.out.println("Counter()");
      }
      public int next() {
    	  System.out.println(name); // Access local final
        return count++;
      }
    };
  }	
  public static void main(String[] args) {
    LocalInnerClass lic = new LocalInnerClass();
    Counter
      c1 = lic.getCounter("Local inner "),
      c2 = lic.getCounter2("Anonymous inner ");
    for(int i = 0; i < 5; i++)
    	System.out.println(c1.next());
    for(int i = 0; i < 5; i++)
    	System.out.println(c2.next());
  }
} /* Output:
LocalCounter()
Counter()
Local inner 0
Local inner 1
Local inner 2
Local inner 3
Local inner 4
Anonymous inner 5
Anonymous inner 6
Anonymous inner 7
Anonymous inner 8
Anonymous inner 9
*///:~

10.12内部类标识符 $

相关文章
相关标签/搜索