博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《java编程思想》学习笔记——内部类五
阅读量:6324 次
发布时间:2019-06-22

本文共 12737 字,大约阅读时间需要 42 分钟。

hot3.png

10.5 在方法和作用域内的内部类

1、可以在一个方法里面或者任意的作用域内定义内部类。这么做有两个理由:

(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);    }    public static void mian(String[] args)    {        Parcel5 p = new Parcel5();        Destination d = p.destination("");    }}

2、以下的内部类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匿名内部类

1、使用默认构造器

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

2、基类需要一个有参数的构造器

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

3、如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数时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");  }}

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

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再访工厂方法 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);  }}

2、例二:

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嵌套类

1、如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static.这通常陈伟嵌套类。

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

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

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

3、普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有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接口内部的类 1、正常情况下,不能在接口内部放置任何代码,但嵌套可以作为接口的一部分。你放的接口的任何类都自动地是public和static的。

2、如果你想要创建某些公共代码,使得它们可以被某个接口的所有实现所公用,那么使用接口内部类的嵌套类会显得很方便。

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

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

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为什么需要内部类

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

2、内部类允许继承多个非接口类型。

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

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

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

4、如果使用内部类,还可以获得其他一些特性

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

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

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

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

10.8.1闭包与回调

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 operation112Other operation2Other operation3*///:~

10.8.2内部类与控制框架

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

10.9内部类的继承

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

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内部类可以被覆盖吗

1、当继承了某个外围类的时候,内部类并没有发生什么特别神奇的变化。这两个内部类是完全独立的实体,各自在自己的命名空间内。

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局部内部类

1、唯一的理由是,我们需要一个命名的构造器,或是需要重载构造器,而匿名内部类只能用于实例初始化。所以使用局部类而不使用匿名内部类的另一个理由是,需要不只一个该内部类的对象。

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 0Local inner 1Local inner 2Local inner 3Local inner 4Anonymous inner 5Anonymous inner 6Anonymous inner 7Anonymous inner 8Anonymous inner 9*///:~

10.12内部类标识符 $

转载于:https://my.oschina.net/u/2427561/blog/1583700

你可能感兴趣的文章
RocketMQ原理解析-Broker
查看>>
【转】【Linux】linux下xargs命令
查看>>
sql server<> != 从数据类型varchar转换为numeric 时出错
查看>>
利用命令行发邮件
查看>>
mac install brew
查看>>
hdu1285 确定比赛名次(拓扑排序多种方法)
查看>>
mysql在linux下的安装
查看>>
php删除数组中指定值的元素
查看>>
第六天-request response\13-request乱码.avi;
查看>>
git版本超前了N个版本且落后了N个版本的解决办法
查看>>
QSettings读写注冊表、配置文件
查看>>
Elasticsearch之CURL命令的mget查询
查看>>
Ubuntu升级出现/boot空间不足解决(转)
查看>>
linux目录结构介绍
查看>>
静态切割窗体+关联对话框
查看>>
HDU 4968 Improving the GPA(dp)
查看>>
【iCore4 双核心板_FPGA】例程四:Signal Tapll 实验——逻辑分析仪
查看>>
注册使用GAC—Global Assembly Cache(.NET)(转载)
查看>>
“System.Runtime.InteropServices.COMException”类型的第一次机会异常在 ESRI.ArcGIS.Version.dll 中发生...
查看>>
Redis:高性能文件缓存key-value储存
查看>>