定义与创建

将一个类定义放在另一个类、方法、作用域、匿名类等地方,就是内部类;内部类只能由外部类对象创建(通过外部方法或者.new方法),内部类对象创建时必须已经有一个外部类对象,并且与之连接(在内部类中会创建一个指向其外部类对象的引用),内部类可以访问到外部类对象的所有成员(包括private);

如:示例代码中,在Parcel类的内部定义了内部类:Contents和Destination,在外部类方法ship中,可以直接创建内部类对象;但是在类外部,只能想创建外部类对象q,然后再通过该对象的contents()和to()方法来创建内部类对象;或者可以通过q2.new来调用内部类的构造方法;注意内部类的引用类型格式是OutClass.InnerClass;

在内部类中,可以使用OutClass.this来调用外部类对象(必然存在该对象,且和内部类对象连接);

当内部类指定是private时,只能在类的内部调用该内部类,外部类对象无法访问并且创建该内部类对象;protected内部类则只有外部类的子类可以访问;通过创建private内部类可以通过类来完成一些工作并且隐藏所有类定义的细节;

在作用域中使用类时,超过作用域该类就无法被访问;如示例代码展示了几种内部类的定义方式;

注意在Parcel7、Parcel8中使用了匿名类,通过基类和接口创建匿名类对象的同时创建类的定义,匿名类的意义为:创建继承自一个基类或者接口的匿名类对象,默认添加继承关系;

使用匿名类时,不要忘记类定义后的分号;

如果如Parcel9中匿名内部类使用外部类中定义的对象,那么编译器会要求其参数引用是final的(如外部类方法destination中),否则将会出错;

如AnonymousConstructor中,可以通过对实例的初始化实现一个匿名构造器功能;如果匿名类中没有直接使用i,则外部方法的参数不需要指定是final的;又如Parcel10中,由于if语句并不能在初始化时被执行,所有匿名类中对实例化的初始化实际效果就相当于是构造器;

匿名内部类只能实现接口和扩展类的其中一个;

使用内部类改进工厂方法

在上一节最后使用到了工厂方法,将多个子类的构造器使用通用接口包装,然后对该接口进行调用即可实现多种子类的构造活动;而由于子类的构造器是不可见的,并且没有必要创建作为工厂的具名类,而只需要一个单一的工厂对象即可,使用匿名内部类改进后的代码为:示例代码;改进后的代码更加具有实际意义(消除了每个子类单独的工厂类);

嵌套类与单元测试

当不需要内部类和外部类的对象之间有联系时,可以将内部类声明为static,这种方式称为嵌套类;

嵌套类由于申明了static,并不像内部类一样,具有一个外部类的对象引用;一旦创建了嵌套类,就说明了嵌套类中的对象并不需要外部类对象的引用,并且不能从嵌套类的对象中访问非静态的外部类对象,没有new方法和this;

正常情况下,接口中是不能放置任何代码的,但是嵌套类可以作为接口的一部分;由于接口中所有的成员都将变为static和public,类也一样,一旦放入接口中,该类就是一个嵌套类;如:示例代码

通过在每个类中添加main()方法可以完成单元测试的工作,但是这样做会将带上已经编译后的额外代码,通过将main方法放置到嵌套类中,可以优化单元测试,如: 示例代码;在编译之后,每个嵌套类(以及内部类)都会产生一个OutClass$InnerClass.class类似的文件,单元测试的类也一样,只要运行java TestBed\$Tester即可进行测试工作;只要在发布时,简单的将该文件删除就可以删除单元测试的内容;

内部类应用

1. 实现多重继承

通过使用内部类独立继承自一个接口的实现完成多重继承的工作;同时由于外部类不能同时继承自两个基类,只能通过内部类完成多重继承;

如:示例代码中,A、B接口可以通过X、Y两种方式实现多重继承;C、D抽象类则只能通过Z来实现多重继承;

2. 在同一个外围类中,可以使用多个内部类以不同的方式实现同一个接口,这样可以在同一个类中完成一个接口的多种实现而不用另外创建一个新类,通过这种方式可以形成更加清晰的代码结构;如Sequence中实现ForwardSelector和ReverseSelector两种Selector接口实现:

interface Selector{

    char getCharAt(int i);

}

 

class Sequence {

    private String s;

        Sequence(String s){

        this.s = s;

    }

    private Selector fs(){

        return new Selector(){

             public char getCharAt(int i){

                 return s.charAt(i);

             }

        };

    }

    private Selector rs(){

        return new Selector(){

             public char getCharAt(int i){

                 int index = s.length() - i;

                 return s.charAt(index);

             }

        };

    }

    public char forwardSelector(int i){return fs().getCharAt(i);}

    public char reverseSelector(int i){return rs().getCharAt(i);}

}

3. 实现回调

当一个外部类继承自一个接口的实现时,可以通过内部类完成接口的另一个实现;并在适当的适合进行选择;如:示例代码 中,Callee2继承自MyIncrement,该类是接口Incrementable的一个实现,Callee2在某些时候需要使用继承来的方法,但是同时如果又有对该接口的另外实现,则可以通过新建内部类:Closure来完成,在Closure中返回一个Callee2的钩子,并且只能调用increment方法;并且通过设置内部类为private以及getCallbackReference()方法来隐藏实现过程;

4. 控制框架的编写;

控制框架往往由单个类来创建,用内部类来表示解决问题所必须的各种不同的action(),从而使得实现的细节被封装起来;

注意要点

1. 内部类的继承

由于内部类必须要和一个外部类的对象连接才可以被实例化,所以在继承一个内部类时,在构造方法中应该引用一个其外部类的对象,并且必须使用:

outclassReference.super()

的方式进行引用;如:

class WithInner{

    class Inner{}

}

 

public class InheritInner extends WithInner.Inner {

    InheritInner(WithInner wi){

        wi.super();

    }

}

2. 内部类的覆盖

内部类和外部类是完全独立的个体,各自在自己的命名空间内,如:示例代码中,在new BigEgg()时,先调用基类构造方法,打印New Egg()以及调用基类的内部类Yolk构造方法;此时,BigEgg()中的Yolk类没有起到作用,但是,如果添加BigEgg的构造方法,并且在其中创建Yolk内部类,则是可以完成覆盖的(其实是生成了一个同名方法);真正完成内部类的覆盖,则需要使内部类也继承基类中的内部类,并完成改写操作,如下面的示例;

示例代码中还可以看到内部类的初始化过程:

基类的内部类 -> 基类 -> 基类内部类 -> 子类内部类 -> 子类;

3. 局部内部类

当一个内部类在作用域内创建时,则会局部内部类,局部内部类不能访问说明符,不是外部类的一部分,而是作用域的一部分,所以可以访问作用域内的常量以及外部类的成员;

局部作用域常在方法体内定义,并且被用来重载构造器,或者生成多个内部类对象等;

thinkinginjava学习笔记09_内部类的更多相关文章

  1. Java学习笔记之---内部类

    Java学习笔记之---内部类 (一)成员内部类 内部类在外部使用时,无法直接实例化,需要借助外部类信息才能实例化 内部类的访问修饰符可以任意,但是访问范围会受到影响 内部类可以直接访问外部类的成员, ...

  2. Java学习笔记:内部类/匿名内部类的全面介绍

    编写java程序时,一般一个类(或者接口)都是放在一个独立的java文件中,并且类名同文件名(如果类是public的,类名必须与文件名一致:非public得,无强制要求).如果想把多个java类放在一 ...

  3. 3)Java学习笔记:内部类

    什么是内部类 内部类是指在一个外部类的内部再定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的.内部类可为静态,可用protected和private修饰(而外部类只能使用public和 ...

  4. thinkinginjava学习笔记07_多态

    在上一节的学习中,强调继承一般在需要向上转型时才有必要上场,否则都应该谨慎使用: 向上转型和绑定 向上转型是指子类向基类转型,由于子类拥有基类中的所有接口,所以向上转型的过程是安全无损的,所有对基类进 ...

  5. thinkinginjava学习笔记06_复用类

    MarsEdit粘代码好麻烦,所有代码交给github:https://github.com/lozybean/MyJavaLearning 复用一个类常用的两种方式:组合.继承: 组合 将对象引用置 ...

  6. thinkinginjava学习笔记05_访问权限

    Java中访问权限等级从大到小依次为:public.protected.包访问权限(没有关键词).private: 以包访问权限为界限,public.protected分别可以被任意对象和继承的对象访 ...

  7. thinkinginjava学习笔记04_初始化与清理

    java沿用了c++的构造器,使用一个和类名完全一样的方法作为类的构造器,可以有多个构造器来通过不同的参数进行构造,称为重载:不仅是构造器可以重载,其他方法也一样通过不同的形参以及不同的返回值来实现重 ...

  8. thinkinginjava学习笔记01_导论

    初学java,希望旅途愉快  :) 类型决定对象的接口,(有人认为类是类型的特定实现),接口确定对象所能发出的请求(消息),满足请求的代码和隐藏的数据一起构成实现: 对象设计时,应该很好地完成一项任务 ...

  9. 【原】Java学习笔记025 - 内部类

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 内部类(嵌套类): ...

随机推荐

  1. js+画曲线和圆 并限制圆的渲染范围

    通过三个点的坐标可确定一条双曲线. 公式: 1)y=ax^2+bx+c; 2) y=a(x-k)+h; 通过已知三点可确定a,b,c,h,k 2.通过圆心坐标(a,b)和半径r可确定一个圆,和已知的x ...

  2. Ambari源代码分析之Resource.Type与ResourceProvider相应关系

    前面提到.每一种Resource都相应一个ResourceProvider,以下给出其相应关系: Resource.Type ResourceProvider Workflow WorkflowRes ...

  3. STM32W108无线射频模块通用IO接口应用实例

    STM32W108无线射频模块通用IO接口应用实例 本实例编写STM32W108的GPIO測试程序,通过控制GPIO引脚,实现对LED灯的控制. 开发环境与硬件说明 硬件:STM32W108无线开发板 ...

  4. 蓝牙核心技术概述(五):蓝牙协议规范(irOBEX、BNEP、AVDTP、AVCTP)

    关键词:蓝牙核心技术协议  irDA BNEP  AVDTP AVCTP 作者:xubin341719(欢迎转载,请注明作者,请尊重版权,谢谢! )欢迎指正错误,共同学习.共同进步!! 下载链接:Bl ...

  5. clientHeight、offsetHeight、scrollHeight详解

    网页可见区域宽: document.body.clientWidth; 网页可见区域高: document.body.clientHeight; 网页可见区域宽: document.body.offs ...

  6. Spring Boot实战之逐行释义HelloWorld

    一.前言  研究Spring boot也有一小段时间了,最近会将研究东西整理一下给大家分享,大概会有10~20篇左右的博客,整个系列会以一个简单的博客系统作为基础,因为光讲理论很多东西不是特别容易理解 ...

  7. spring mvc对静态资源的访问

    如果我们的项目使用的是springmvc,在web.xml中会有一段这的配置. <servlet> <servlet-name>springMvc</servlet-na ...

  8. androidstudio连接SCM Manager上的Git库

    1.在SCM Manager里创建一个Git库 在androidstudio里选中从版本控制里导入 输入git库的地址,接下来一路点击下一步 完成之后会可以在工程里创建文件或者从别的地方把完整项目拷贝 ...

  9. 【转】Android开发之数据库SQL

    android中的应用开发很难避免不去使用数据库,这次就和大家聊聊android中的数据库操作. 一.android内的数据库的基础知识介绍 1.用了什么数据库 android中采用的数据库是SQLi ...

  10. (一)最小的Django

    本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 本文基本内容均出自<Lightweight Django>(中文为<轻量级D ...