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内部类标识符 $