内部类

内部类:将一个类的定义放在另一个类的定义内部。内部类机制可以把逻辑相关的类组织在一起,并控制位于内部的类的可视性。

内部类与组合是完全不同的概念。

内部类不仅是一种代码隐藏机制(将类置于其他类的内部),还能与外围类通信。

类似于外围类的成员的内部类。

2-1 链接到外部类

内部类可以访问其外围类的 所有字段和方法(所有成员)。创建一个普通内部类对象需要先创建其外围类的对象,然后使用该外围类对象取创建内部类对象。当某个外围类创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。然后就可使用这个引用来访问外围类对象的成员。

运行结果为:

2-2 使用 外围类名.this

如果需要在内部类中获取外围类对象的引用,可以使用 外围类名.this 来获取

运行结果为:

2-3 使用 外围类对象.new

要直接创建普通内部类对象,必须使用外围类的对象来创建该内部类对象。这也解决了内部类名字作用域的问题,即使用外围类对象只能创建定义在外围类中的内部类的对象。

因此,就不必声明(也不能声明)外围类的类名,如inner = dot.new DotNew.Inner();

在拥有外围类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗地连接到创建它的外围类对象上。但是,如果你创建的是嵌套类(静态内部类),那就不需要先创建外围类对象。

2-4 外围类访问内部类

先看一下内部类访问外围类成员的方式:如果想要访问外围类的某个成员,直接使用外围类这个成员的名字就可以。

但是,如果外围类要访问内部类的成员的话就不能使用这种方式(即直接使用内部类成员的名字):

正确的方式应该先创建内部类的对象再通过此对象去访问:

内部类可以直接通过外围类的成员名去访问外围类成员,而外围类需要通过内部类的对象去访问内部类成员。造成这种差别的原因可能是:

在使用内部类对象时,可保证其外围类对象一定被创建了,且内部类对象一定有一个指向其外围类对象的引用,所以内部类可以通过成员名直接访问(可能编译器会在成员名前自动拼接 外围类对象引用.);而在使用外部类对象时,并不能保证内部类对象一定被创建了,所以需要先创建内部类对象,然后通过这个内部类对象去访问内部类成员。

可以在一个方法里面或在任意作用域(方法的作用域:if(isOk){作用域}、类的作用域)中定义内部类。这么做有两个理由:

3-1定义在方法中的类

在方法的作用域内(而不是在其他类的作用域内)创建一个完整的类,这被称作局部内部类。

运行结果为:

注意:

1.PDestination类是destination方法的一部分,而不是Parcel5的一部分。所以,在destination()之外不能访问PDestination;

2.在destination()方法中定义了内部类PDestination,并不意味着一旦destination()方法执行完毕,PDestination就不可用了。

3-2定义在方法内作用域中的类

TrackingSlip类被嵌入在if语句的作用域内,这并不是说该类本身的创建是有条件的,它其实会与其他类一起被编译。然而,在定义TrackingSlip的作用域之外,它是不可用的;除此之外,它与普通类一样。

3-3实现了接口的匿名内部类

return语句的含义为:创建一个实现(继承)了Contents接口(类)的匿名类对象。

3-4扩展了有非默认构造器的类的匿名内部类

有非默认构造器的类Wrapping

匿名类Parcel8扩展Wrapping类

运行结果为:

目前来看,定义匿名内部类的方式为:

1.当是 new 接口名()时,创建的就是一个实现类对象;

2.当是 new 基类名(基类构造器的参数)时,创建的是一个子类对象,但在创建子类对象中包含的基类对象时调用的就是new关键字后 指定的基类构造器

3-5执行字段初始化的匿名内部类

在匿名类中定义字段时,还能够对其执行初始化操作。

运行结果为:

如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象(可以是方法传入的参数,也可以是外围类的成员),那么编译器会要求 这个对象是final的。

注:匿名内部类(子类)本身使用外部对象才要求是final的,但如果只是基类使用而匿名内部类自身不使用,则不需要是final的。

上面的例子中的匿名内部类使用的在其外部定义的对象是通过方法的参数传入的,也可以直接使用外围类的成员(private成员默认是final的)。

运行结果为:

3-6通过实例化实现构造的匿名内部类

匿名类因为没有名字,所以不可能有构造器。

通过实例初始化(本质就是通过 普通代码块),就能达到为匿名内部类创建一个构造器的效果。

运行结果为:

匿名内部类与正规的继承相比有些受限,因为匿名内部类 既可以扩展类,也可以实现接口,但是不能两者兼备。而且如果是实现接口,也只能实现一个接口。

如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。这通常称之为嵌套类或者静态内部类。

普通的内部类对象隐式地保存了一个引用,指向它的外围类对象。而嵌套类对象就没有这个引用,这意味着:

普通的内部类中不能有static数据和static字段,也不能包含嵌套类(也是static的),但是嵌套类可以包含这些静态的东西。其原因可认为是:

普通内部类可看作是外围类的非静态成员,要求它的初始化必须在其外围类对象创建之后进行。在创建内部类对象的时候,会先加载外围类,再加载内部类。类加载完成后就会初始化类的静态成员,如果内部类有静态成员,那么就会在类加载后初始化内部类的静态成员,但这个时候其外围类对象还未创建,这与要求冲突。所以不允许普通内部类包含静态成员。

这个例子中还有一个需要注意的地方:外围类能直接访问静态内部类的静态私有成员(构造器)。所以总结一下外围内访问内部类的规律:

4-1接口中的类

接口中的变量默认是public static final的;

接口中的方法默认是public的;

接口中的类默认是public static的,也就是说,接口中的类默认是静态内部类。

运行结果为:

Original: https://www.cnblogs.com/certainTao/p/14844775.html
Author: certainTao
Title: 内部类

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/585275/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Python 中 map() zip() list() 函数的介绍

    map() map(function , iterable, ….) : 依次将函数function作用在可迭代的list上,并返回对应的函数返回值,组成新的list(…

    Linux 2023年6月7日
    096
  • Windows 10安装

    使用U盘安装操作系统教程 本教程介绍如何使用U盘安装操作系统,以安装Windows 10过程作为举例。 1 获取操作系统iso镜像文件 获取操作系统ISO镜像文件有很多途径,此处介…

    Linux 2023年6月13日
    085
  • Docker下部署LNMP黄金架构

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月7日
    093
  • 百钱买百鸡问题

    百钱买百鸡问题 题目:公元前5世纪末,中国古代数学家张丘建在他的《算经》中提出了著名的 “百钱买百鸡问题”:鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,…

    Linux 2023年6月7日
    098
  • Pycharm设置python文件头

    设置路径为: File->Setting->Editor->File and code Templates->Python Script 可用的预定义文件模…

    Linux 2023年6月8日
    0102
  • 附028.Kubernetes_v1.20.0高可用部署架构二

    kubeadm介绍 kubeadm概述 kubeadm功能 本方案描述 部署规划 节点规划 初始准备 互信配置 其他准备 集群部署 相关组件包 正式安装 部署高可用组件I Keep…

    Linux 2023年6月13日
    0150
  • (转)WEB页面导出为Word文档后分页&横向打印的方法

    WEB页面导出为Word文档后分页&横向打印的方法title >HEAD >/// * * @param {Object} cont 要导出的html元素内容的…

    Linux 2023年6月7日
    0109
  • Linux01:常用的基本命令及概述及环境搭建(狂神说)

    Linux学习 一、入门概述 我们为什么要学Linux Linux诞生了这么多年,以前还喊着如何能取代windows系统,现在这个口号已经小多了,任何事物发展都有其局限性都有其天花…

    Linux 2023年5月27日
    066
  • Docker安装使用–Centos

    前言 Docker安装使用 安装步骤 卸载旧版本 安装utils 配置utils的存储库 安装Docker 安装指定版本Docker 验证安装 官网安装说明 阿里云镜像加速 Doc…

    Linux 2023年6月7日
    080
  • 页面国际化

    页面国际化 有的时候,我们的网站会去涉及中英文甚至多语言的切换,这时候我们就需要对页面进行国际化设计了。 6.1 准备工作 在IDEA中统一设置properties的编码格式 6….

    Linux 2023年6月14日
    099
  • docker使用

    什么是虚拟化 在计算机中,虚拟化(英语:Virtualization)是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体…

    Linux 2023年6月14日
    079
  • MySQL架构和存储引擎、系统默认数据库介绍

    采用C/S架构,即客户端/服务器。客户端和服务器区分开,通过客户端发送请求来和服务器交互。 存储引擎:MySQL管理数据文件的一种技术。 myisam innodb myisam特…

    Linux 2023年6月7日
    098
  • Ubuntu下交换Alt和Ctrl (适用于任何按键修改)

    在 Ubuntu 下交换 Alt和 Ctrl键: sudo vim /usr/share/X11/xkb/keycodes/evdev 或使用系统默认编辑器打开: [En] Or …

    Linux 2023年5月27日
    093
  • Redis配置参数详解

    Redis是一个应用非常广泛的高性能Key-Value型数据库,与memcached类似,但功能更加强大!本文将按照不同功能模块的方式,依次对各个功能模块的配置参数进行详细介绍。 …

    Linux 2023年5月28日
    077
  • 3-在Django中使用使用数据库

    数据库设置 在上一章节中学习了如何创建Django项目,在Django项目中创建web应用,以及如何在Django主程序的URL中引用web应用中的URL。下面来了解如何在Djan…

    Linux 2023年6月7日
    0101
  • 数据结构 二叉树

    cpp;gutter:true;</p> <h1>include</h1> <p>using namespace std;</…

    Linux 2023年6月13日
    068
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球