2019独角兽企业重金招聘Python工程师标准>>>

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 ParcelDestinationimplements 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 operation
1
1
2
Other operation
2
Other operation
3
*///:~

10.8.2内部类与控制框架

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

10.9内部类的继承

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

class WithInner {class Inner {}
}public class InheritInner extends WithInner.Inner {//! InheritInner() {} // Won't compileInheritInner(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 constructorSystem.out.println("LocalCounter()");}public int next() {System.out.println(name); // Access local finalreturn 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 finalreturn count++;}};}  public static void main(String[] args) {LocalInnerClass lic = new LocalInnerClass();Counterc1 = 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内部类标识符 $

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

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

  1. Java编程思想学习笔记-第11章

    <?xml version="1.0" encoding="utf-8"?> Java编程思想学习笔记-第11章 Java编程思想学习笔记-第11章 ...

  2. JAVA编程思想学习笔记——第一章 对象导论

    搞了一年多java,野路子出身,发现java基础这块还是相当的薄弱!故决定学习<Java编程思想>这本书.在此把学习的知识点记录下! 面向对象的五大特性 1.万物皆为对象 2.程序是对象的 ...

  3. Java编程思想学习笔记4 - 序列化技术

    今天来学习下Java序列化和反序列化技术,笔者对<Java编程思想>中的内容,结合网上各位前辈的帖子进行了整理和补充,包括: 序列化概述 Java原生序列化技术 Hessian序列化技术 ...

  4. Java编程思想 学习笔记1

    一.对象导论 1.抽象过程 Alan Kay曾经总结了第一个成功的面向对象语言.同时也是Java所基于的语言之一的Smalltalk的五个基本特性,这些特性表现了纯粹的面向对象程序设计方式 1)万物皆 ...

  5. Java编程思想 学习笔记7

    七.复用类 1.组合语法 在新的类中产生现有类的对象.由于新的类是由现有类的对象所组成,所以这种方法叫做组合. 类中域为基本类型时能够自动被初始化为零.对象引用被初始化为null. 编译器不是简单地为 ...

  6. java编程思想 学习笔记(2)

    第二章     一切都是对象 用引用(reference)操纵对象 String s = "asdf"; String s; 但这里所创建的只是引用,并不是对象.如果此时向s 发送 ...

  7. java编程思想学习笔记(第七章:复用类)

    复用代码是java众多引人注目的功能之一.但是要想成为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须能够做更多的事情. 7.1组合语法 将对象引用置于新类中.每一个非基本类型的对象 ...

  8. Java并发编程艺术学习笔记(五)

    Java并发编程艺术学习笔记(五) Java并发容器和框架 Java为开发者也提供了许多开发容器和框架,可以从每节的原理分析来学习其中精妙的并发程序. 一.ConcurrentHashMap的实现原理 ...

  9. JAVA编程思想读书笔记(三)--RTTI

    接上篇JAVA编程思想读书笔记(二) 第十一章 运行期类型判定 No1: 对于作为程序一部分的每个类,它们都有一个Class对象.换言之,每次写一个新类时,同时也会创建一个Class对象(更恰当的说, ...

  10. 01.Java 编程入门学习笔记20210307

    Java 编程入门学习笔记-day01 第0章:编程入门 1.计算机的概述 计算机 = 硬件 + 软件 1.1硬件:冯诺依曼体系 CPU: CPU的衡量标准:速度的计量单位是赫兹(Hz),1Hz相当于 ...

最新文章

  1. spark 序列化错误 集群提交时_【问题解决】本地提交任务到Spark集群报错:Initial job has not accepted any resources...
  2. 【pandas学习笔记】DataFrame
  3. python画笑脸-用Python画滑稽
  4. 基于TableStore的海量气象格点数据解决方案实战
  5. caffe linux 教程,CentOS7安装Caffe的教程详解
  6. Android 第三方库RxLifecycle使用
  7. python回车换行怎么不行_使用Python编写换行符时避免写入回车'\r'
  8. 公司新来的小可爱,竟然把内存搞崩了!
  9. php 数组处理函数,PHP数组处理函数举例
  10. Intel Skylake (Client) 架构/微架构/流水线 (2) - 前端
  11. windows cmd命令行命令
  12. 移动端图片上传老失败
  13. lua把userdata写入mysql_Lua中的userdata
  14. 第八课 实战重启验证注册机制
  15. Python调用go function
  16. WPS文字设置奇偶页眉、下划线的方法步骤
  17. 2020蓝桥杯python——纪念日
  18. C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(二十四) Be careful!前方怪物出没
  19. win10照片查看器_Win10 下好用的免费无广告看图软件 XnView
  20. 云原生系列六:容器和Docker

热门文章

  1. org/springframework/core/ErrorCoded
  2. php文件包含漏洞(input与filter)
  3. 对象拷贝类PropertyUtils,BeanUtils,BeanCopier的技术沉淀
  4. Centos Git1.7.1升级到Git2.2.1
  5. 揭秘物联网之城无锡鸿山的科技密码
  6. Google I/O 2019上提及的Javascript新特性
  7. 写了一个puppet web 管理界面,打算开源
  8. C/C++ VS java
  9. SecureRandom
  10. 安全证书导入到java中的cacerts证书库