《java编程思想》学习笔记——内部类五
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编程思想》学习笔记——内部类五相关推荐
- Java编程思想学习笔记-第11章
<?xml version="1.0" encoding="utf-8"?> Java编程思想学习笔记-第11章 Java编程思想学习笔记-第11章 ...
- JAVA编程思想学习笔记——第一章 对象导论
搞了一年多java,野路子出身,发现java基础这块还是相当的薄弱!故决定学习<Java编程思想>这本书.在此把学习的知识点记录下! 面向对象的五大特性 1.万物皆为对象 2.程序是对象的 ...
- Java编程思想学习笔记4 - 序列化技术
今天来学习下Java序列化和反序列化技术,笔者对<Java编程思想>中的内容,结合网上各位前辈的帖子进行了整理和补充,包括: 序列化概述 Java原生序列化技术 Hessian序列化技术 ...
- Java编程思想 学习笔记1
一.对象导论 1.抽象过程 Alan Kay曾经总结了第一个成功的面向对象语言.同时也是Java所基于的语言之一的Smalltalk的五个基本特性,这些特性表现了纯粹的面向对象程序设计方式 1)万物皆 ...
- Java编程思想 学习笔记7
七.复用类 1.组合语法 在新的类中产生现有类的对象.由于新的类是由现有类的对象所组成,所以这种方法叫做组合. 类中域为基本类型时能够自动被初始化为零.对象引用被初始化为null. 编译器不是简单地为 ...
- java编程思想 学习笔记(2)
第二章 一切都是对象 用引用(reference)操纵对象 String s = "asdf"; String s; 但这里所创建的只是引用,并不是对象.如果此时向s 发送 ...
- java编程思想学习笔记(第七章:复用类)
复用代码是java众多引人注目的功能之一.但是要想成为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须能够做更多的事情. 7.1组合语法 将对象引用置于新类中.每一个非基本类型的对象 ...
- Java并发编程艺术学习笔记(五)
Java并发编程艺术学习笔记(五) Java并发容器和框架 Java为开发者也提供了许多开发容器和框架,可以从每节的原理分析来学习其中精妙的并发程序. 一.ConcurrentHashMap的实现原理 ...
- JAVA编程思想读书笔记(三)--RTTI
接上篇JAVA编程思想读书笔记(二) 第十一章 运行期类型判定 No1: 对于作为程序一部分的每个类,它们都有一个Class对象.换言之,每次写一个新类时,同时也会创建一个Class对象(更恰当的说, ...
- 01.Java 编程入门学习笔记20210307
Java 编程入门学习笔记-day01 第0章:编程入门 1.计算机的概述 计算机 = 硬件 + 软件 1.1硬件:冯诺依曼体系 CPU: CPU的衡量标准:速度的计量单位是赫兹(Hz),1Hz相当于 ...
最新文章
- spark 序列化错误 集群提交时_【问题解决】本地提交任务到Spark集群报错:Initial job has not accepted any resources...
- 【pandas学习笔记】DataFrame
- python画笑脸-用Python画滑稽
- 基于TableStore的海量气象格点数据解决方案实战
- caffe linux 教程,CentOS7安装Caffe的教程详解
- Android 第三方库RxLifecycle使用
- python回车换行怎么不行_使用Python编写换行符时避免写入回车'\r'
- 公司新来的小可爱,竟然把内存搞崩了!
- php 数组处理函数,PHP数组处理函数举例
- Intel Skylake (Client) 架构/微架构/流水线 (2) - 前端
- windows cmd命令行命令
- 移动端图片上传老失败
- lua把userdata写入mysql_Lua中的userdata
- 第八课 实战重启验证注册机制
- Python调用go function
- WPS文字设置奇偶页眉、下划线的方法步骤
- 2020蓝桥杯python——纪念日
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(二十四) Be careful!前方怪物出没
- win10照片查看器_Win10 下好用的免费无广告看图软件 XnView
- 云原生系列六:容器和Docker
热门文章
- org/springframework/core/ErrorCoded
- php文件包含漏洞(input与filter)
- 对象拷贝类PropertyUtils,BeanUtils,BeanCopier的技术沉淀
- Centos Git1.7.1升级到Git2.2.1
- 揭秘物联网之城无锡鸿山的科技密码
- Google I/O 2019上提及的Javascript新特性
- 写了一个puppet web 管理界面,打算开源
- C/C++ VS java
- SecureRandom
- 安全证书导入到java中的cacerts证书库