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

内部类基本概念

  • 可将一个类的定义置于另一个类定义的内部
  • 内部类允许将逻辑相关的类组织在一起,并控制位于内部的类的可见性
  • 甚至可将内部类定义于一个方法或者任意作用域内!
  • 当然,内部类 ≠ 组合
  • 内部类拥有其外围类 所有元素的 访问权
  • 更有甚,嵌套多层的内部类能透明地访问所有它所嵌入的外围类的所有成员

一个典型的例子:利用 Java内部类 实现的 迭代器模式

// 接口
-------------------------------------------------------------
public interface Selector {boolean end();Object current();void next();
}
// 外部类(集合类) + 内部类(迭代器类)
-------------------------------------------------------------
public class Sequence { // 外部类(代表一个集合类)private Object[] items;private int next = 0;public Sequence( int size ) {items = new Object[size];}public void add( Object x ) {if( next < items.length )items[next++] = x;} // 迭代器类:实现了 Selector接口的 内部类private class SequenceSelector implements Selector {private int i = 0;public boolean end() { return i == items.length; }public Object current() { return items[i]; }public void next() {if( i<items.length )++i;}}public Selector selector() { // 该函数也表明了:内部类也可以向上转型,这样在外部就隐藏了实现细节!return new SequenceSelector();}public static void main( String[] args ) {Sequence sequence = new Sequence(10);for( int i=0; i<10; ++i ) { // 装填元素sequence.add( Integer.toString(i) );}Selector selector = sequence.selector(); // 获取iterator!while( !selector.end() ) {print( selector.current() + " " );selector.next();}}
}
// 输出
-------------------------------------------------------------
0 1 2 3 4 5 6 7 8 9

.this 与 .new 的使用场景

.this用于在内部类中生成对其外部类对象的引用之时,举例:

public class DotThis {void f() { print("DotThis.f()"); }public class Inner { // 内部类public DotThis outer() { // 返回外部类对象的引用return DotThis.this; // 若直接返回this,那指的便是内部类自身}}public Inner inner() { return new Inner(); }public static void main( String[] args ) {DotThis dt = new DotThis();DotThis.Inner dti = dt.inner();dti.outer().f(); // 输出 DotThis.f()}
}

.new用于直接创建内部类的对象之时,距离:

public class DotNew {public class Inner { } // 空内部类public static void main( String[] args ) {DotNew dn = new DotNew();DotNew.Inner dni = dn.new Inner(); //注意此处必须使用外部类的对象,而不能直接 DotNew.Inner dni = new DotNew.Inner()}
}

嵌套类(static类型的内部类)

嵌套类是无需依赖其外部类的对象的。非static内部类通过一个特殊的this链接到其外围类的对象,而static类型的内部类无此this引用。

接口与内部类有着很有趣的关系: 放到接口中的任何类自动都是public且static,即接口中的任何类都是嵌套类,我们甚至可以在接口的内部类中去实现其外围接口,举例:

public interface ClassInInterface {void howdy();class Test implements ClassInInterface { // 类Test默认static,所以是嵌套类public void howdy() {print("Howdy!");}public static void main( String[] args ) {new Test().howdy(); }}
}

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

可以称这类为 局部内部类

方法中定义的内部类只能在方法内被使用,方法之外不可访问,举例:

public class Parcel {  // parcel是“包裹”之意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 ); // 只有在方法中才能访问内部类PDestination}public static void main( String[] args ) {Parcel p = new Parcel();Destination d = p.destination( "Hello" );...}
}

更进一步,可在任意作用域内定义内部类,举例:

public class Parcel {private void internalTracking( boolean b ) {if( b ) { // 局部作用域中定义了内部类,作用域之外不可访问!class TrackingSlip {private String id;TrackingSlip( String s ) { id = s; }String getSlip() { return id; }}}}public void track() { interTracking( true ); }public static void main( String[] args ) {Parcel p = new Parcel();p.track();}
}

匿名内部类

直观上看,这种内部类没有“名字”,举例:

public class Parcel {public Contents contents() {return new Contents() { // 此即匿名内部类!!!private int i = 11;public int value() { return i; }}; // !!!注意这里必须要加分号!!!}public static void main( String[] args ) {Parcel p = new Parcel();Contents c = p.contents();}
}

若想将外部的参数传到匿名内部类中(典型的如将外部参数用于对匿名内部类中的定义字段进行初始化时)使用的话,该参数必须final,举例:

public class Parcel {public Destination destination( final String s ) { // final必须!return new Destination() {private String label = s;public String readLabel() { return label; }}; // 分号必须!}public static void mian( String[] args ) {Parcel p = new Parcel();Destination d = p.destination("Hello");}
}

匿名内部类中不可能有命名的显式构造器,此时只能使用实例初始化的方式来模仿,举例(当然下面这个例子还反映了匿名内部类如何参与继承):

// 基类
---------------------------------------------
abstact class Base() {public Base( int i ) {print( "Base ctor, i = " + i );}public abstract void f();
}//主类(其中包含了继承上面Base的派生匿名内部类!)
----------------------------------------------
public class AnonymousConstructor {public static Base getBase( int i ) { // 该处参数无需final,因为并未在下面的内部类中直接使用!return new Base(i){ // 匿名内部类{ // 实例初始化语法!!!print("Inside instance initializer");}public void f() { print( "In anonymous f()" );}}; // 分号必须!}public static void main( String[] args ) {Base base = getBase(47);base.f();}
}// 输出
------------------------------------------
Base ctor, i = 47 // 先基类
Inside instance initializer // 再打印派生类
In anonymous f()

匿名内部类 + 工厂模式 = 更加简洁易懂:

// Service接口
---------------------------------------------------
interface Service {void method1();void method2();
}
// ServiceFactory接口
---------------------------------------------------
interface ServiceFactory {Service getService();
}
// Service接口的实现
---------------------------------------------------
class Implementation1 implements Service {private Implementation1() {} // 构造函数私有public void method1() { print("Implementation1 method1"); }public void method2() { print("Implementation1 method2"); }public static ServiceFactory factory = new ServiceFactory() {public Service getService() {return new Implementation1();}}; // 分号必须!!!
}class Implementation2 implements Service {private Implementation2() {}public void method1() { print("Implementation2 method1"); }public void method2() { print("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 ) {serviceComsumer( Implementation1.factory );serviceComsumer( Implementation2.factory );}
}

总结:为什么需要内部类

内部类可以独立地继承自一个接口或者类而无需关注其外围类的实现,这使得扩展类或者接口更加灵活,控制的粒度也可以更细!

注意Java中还有一个细节:虽然Java中一个接口可以继承多个接口,但是一个类是不能继承多个类的!要想完成该特性,此时除了使用内部类来“扩充多重继承机制”,你可能别无选择,举例:

class D { }               // 普通类
abstract class E { }      // 抽象类class Z extend 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() );}
}

转载于:https://my.oschina.net/architectliuyuanyuan/blog/1611434

Java编程思想学习录(连载之:内部类)相关推荐

  1. Java编程思想学习录(连载之:初始化与清理)

    注: 本文首发于 My 公众号 CodeSheep ,可 长按 或 扫描 下面的 小心心 来订阅 ↓ ↓ ↓ 关于构造器与初始化 无参构造器 = 默认构造器 = 自己未写编译器帮忙自动创建的 若自行定 ...

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

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

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

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

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

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

  5. java编程思想学习(1):抽象

    今天开始java编程思想的导读,希望自己能更好的理解程序.全书1461页,恐怖,尽量一天看十页八. OOP 面向对象程序设计 记录一点东西八 第一个小课程,抽象过程 看看概念 1万物皆为对象 2程序是 ...

  6. Java编程思想学习(一)----对象导论中多态的理解

    1.1抽象过程 1)万物皆对象. 2)程序是对象的集合,他们通过发送消息来告知彼此所要求做的. 3)每个对象都有自己的由其他对象所构成的存储. 4)每个对象都拥有其类型. 5)某一特定类型的所有对象都 ...

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

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

  8. JAVA编程思想学习手账初整理

    redis: 缓存击穿:对于访问过期的key查询数据时,加锁,保证只有一个线程去底层获取数据,并返回结果缓存 缓存穿透:对于访问不存在的key时给出空结果并缓存,或引入布隆过滤器将数据提前缓存在布隆过 ...

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

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

最新文章

  1. .NET下正则表达式应用的四个示例
  2. CF 19D Points 【线段树+平衡树】
  3. Razor master page
  4. brew install php55redis,Mac下安装LNMP环境
  5. 计算机等级考试二级机试题目,计算机等级考试机试模拟试题2007-2版.doc
  6. boost::hana::prepend用法的测试程序
  7. 云原生数据库 2.0:一站式全链路数据管理与服务
  8. 130 秒揭秘 EDAS 3.0 如何平滑应对突发流量高峰,为您的业务保驾护航
  9. 培训机构还能不能信任?
  10. 数智德州,创新未来 | 智慧城市赛题上线山东大赛德州分赛场
  11. js java用var_Java基础———JavaScript基础知识
  12. 网页整个技术文档怎么拷贝_企业文档管理混乱?试试文档管理系统
  13. 调整jvm参数_JVM源码分析之MetaspaceSize和MaxMetaspaceSize的区别
  14. Kmalloc和Vmalloc的区别
  15. Docker学习(四)Docker镜像原理 镜像commit操作补充
  16. 360手机助手电脑版 v2.4.0.1251 官方版
  17. 计算机图形学核心期刊,CCF 推荐国际国内会议及中文核心期刊要目总览
  18. 重读《从菜鸟到测试架构师》-- 测试专家的第一步
  19. 计算机辅助项目管理实验论文,计算机辅助项目管理课程设计--毕设论文.doc
  20. 2021-2027全球与中国雌二醇(CAS 50-28-2)市场现状及未来发展趋势

热门文章

  1. python软件下载手机版-Learn Python中文版app
  2. python 用途-python中的*和**的用途
  3. python基础代码库-python3.4第三方库的安装?python基础代码库
  4. python编程入门书-编程小白的第一本 Python 入门书
  5. ROS调用本地摄像头数据并在rviz里显示
  6. Python常用包的使用
  7. ControlAdvice和ExceptionHandler处理异常的原理与设计
  8. zh-cn 与 zh-hans 是什么关系、有什么区别
  9. android开发过程中的错误:the file dx.jar was not loaded from the SDK folder
  10. POJ 3320 尺取法,Hash,map标记