java内部类的作用分析

2023-10-29

提起Java内部类(Inner Class)可能很多人不太熟悉,实际上类似的概念在C++里也有,那就是嵌套类(Nested Class),关于这两者的区别与联系,在下文中会有对比。内部类从表面上看,就是在类中又定义了一个类(下文会看到,内部类可以在很多地方定义),而实际上并没有那么简单,乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的深入了解,你会发现Java的设计者在内部类身上的确是用心良苦。学会使用内部类,是掌握Java高级编程的一部分,它可以让你更优雅地设计你的程序结构。下面从以下几个方面来介绍:
第一次见面
[java]  view plain copy
  1. public interface Contents {  
  2.     int value();  
  3. }  
  4. public interface Destination {  
  5.     String readLabel();  
  6. }  
  7. public class Goods {  
  8.     private class Content implements Contents {  
  9.         private int i = 11;  
  10.         public int value() {  
  11.             return i;  
  12.         }  
  13.     }  
  14.     protected class GDestination implements Destination {  
  15.         private String label;  
  16.         private GDestination(String whereTo) {  
  17.             label = whereTo;  
  18.         }  
  19.         public String readLabel() {  
  20.             return label;  
  21.         }  
  22.     }  
  23.     public Destination dest(String s) {  
  24.         return new GDestination(s);  
  25.     }  
  26.     public Contents cont() {  
  27.         return new Content();  
  28.     }  
  29. }  
  30. class TestGoods {  
  31.     public static void main(String[] args) {  
  32.         Goods p = new Goods();  
  33.         Contents c = p.cont();  
  34.         Destination d = p.dest("Beijing");  
  35.     }  
  36. }  
 
在这个例子里类Content和GDestination被定义在了类Goods内部,并且分别有着protected和private修饰符来控制访问级别。Content代表着Goods的内容,而GDestination代表着Goods的目的地。它们分别实现了两个接口Content和Destination。在后面的main方法里,直接用 Contents c和Destination d进行操作,你甚至连这两个内部类的名字都没有看见!这样,内部类的第一个好处就体现出来了 隐藏你不想让别人知道的操作,也即封装性。
同时,我们也发现了在外部类作用范围之外得到内部类对象的第一个方法,那就是利用其外部类的方法创建并返回。上例中的cont()和dest()方法就是这么做的。那么还有没有别的方法呢?当然有,其语法格式如下:
outerObject=new outerClass(Constructor Parameters);
outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);
注意在创建非静态内部类对象时,一定要先创建起相应的外部类对象。至于原因,也就引出了我们下一个话题 非静态内部类对象有着指向其外部类对象的引用,对刚才的例子稍作修改:
[java]  view plain copy
  1. public class Goods {  
  2.     private int valueRate = 2;  
  3.     private class Content implements Contents {  
  4.         private int i = 11 * valueRate;  
  5.         public int value() {  
  6.             return i;  
  7.         }  
  8.     }  
  9.     protected class GDestination implements Destination {  
  10.         private String label;  
  11.         private GDestination(String whereTo) {  
  12.             label = whereTo;  
  13.         }  
  14.         public String readLabel() {  
  15.             return label;  
  16.         }  
  17.     }  
  18.     public Destination dest(String s) {  
  19.         return new GDestination(s);  
  20.     }  
  21.     public Contents cont() {  
  22.         return new Content();  
  23.     }  
  24. }  

在这里我们给Goods类增加了一个private成员变量valueRate,意义是货物的价值系数,在内部类Content的方法value()计算价值时把它乘上。我们发现,value()可以访问valueRate,这也是内部类的第二个好处 一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!这是一个非常有用的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引用。Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因。
有人会问,如果内部类里的一个成员变量与外部类的一个成员变量同名,也即外部类的同名成员变量被屏蔽了,怎么办?没事,Java里用如下格式表达外部类的引用:
outerClass.this
有了它,我们就不怕这种屏蔽的情况了。
静态内部类
和普通的类一样,内部类也可以有静态的。不过和非静态内部类相比,区别就在于静态内部类没有了指向外部的引用。这实际上和C++中的嵌套类很相像了,Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用这一点上,当然从设计的角度以及以它一些细节来讲还有区别。
除此之外,在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不止一层)。不过静态内部类中却可以拥有这一切。这也算是两者的第二个区别吧。
局部内部类
是的,Java内部类也可以是局部的,它可以定义在一个方法甚至一个代码块之内。
[java]  view plain copy
  1. public class Goods1 {  
  2.     public Destination dest(String s) {  
  3.         class GDestination implements Destination {  
  4.             private String label;  
  5.             private GDestination(String whereTo) {  
  6.                 label = whereTo;  
  7.             }  
  8.             public String readLabel() {  
  9.                 return label;  
  10.             }  
  11.         }  
  12.         return new GDestination(s);  
  13.     }  
  14.     public static void main(String[] args) {  
  15.         Goods1 g = new Goods1();  
  16.         Destination d = g.dest("Beijing");  
  17.     }  
  18. }  

上面就是这样一个例子。在方法dest中我们定义了一个内部类,最后由这个方法返回这个内部类的对象。如果我们在用一个内部类的时候仅需要创建它的一个对象并创给外部,就可以这样做。当然,定义在方法中的内部类可以使设计多样化,用途绝不仅仅在这一点。
下面有一个更怪的例子:
[java]  view plain copy
  1. public class Goods2 {  
  2.     private void internalTracking(boolean b) {  
  3.         if (b) {  
  4.             class TrackingSlip {  
  5.                 private String id;  
  6.                 TrackingSlip(String s) {  
  7.                     id = s;  
  8.                 }  
  9.                 String getSlip() {  
  10.                     return id;  
  11.                 }  
  12.             }  
  13.             TrackingSlip ts = new TrackingSlip("slip");  
  14.             String s = ts.getSlip();  
  15.         }  
  16.     }  
  17.     public void track() {  
  18.         internalTracking(true);  
  19.     }  
  20.     public static void main(String[] args) {  
  21.         Goods2 g = new Goods2();  
  22.         g.track();  
  23.     }  
  24. }  

你不能在if之外创建这个内部类的对象,因为这已经超出了它的作用域。不过在编译的时候,内部类TrackingSlip和其他类一样同时被编译,只不过它由它自己的作用域,超出了这个范围就无效,除此之外它和其他内部类并没有区别。
匿名内部类
java的匿名内部类的语法规则看上去有些古怪,不过如同匿名数组一样,当你只需要创建一个类的对象而且用不上它的名字时,使用内部类可以使代码看上去简洁清楚。它的语法规则是这样的:
new interfacename(){......}; 或 new superclassname(){......};
下面接着前面继续举例子:
[java]  view plain copy
  1. public class Goods3 {  
  2.     public Contents cont() {  
  3.         return new Contents() {  
  4.             private int i = 11;  
  5.             public int value() {  
  6.                 return i;  
  7.             }  
  8.         };  
  9.     }  
  10. }  

这里方法cont()使用匿名内部类直接返回了一个实现了接口Contents的类的对象,看上去的确十分简洁。
在java的事件处理的匿名适配器中,匿名内部类被大量的使用。例如在想关闭窗口时加上这样一句代码:
[java]  view plain copy
  1. frame.addWindowListener(new WindowAdapter(){  
  2.     public void windowClosing(WindowEvent e){  
  3.        System.exit(0);  
  4.     }  
  5. });   

有一点需要注意的是,匿名内部类由于没有名字,所以它没有构造函数(但是如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数,并在实现的过程中使用super关键字调用相应的内容)。如果你想要初始化它的成员变量,有下面几种方法:
如果是在一个方法的匿名内部类,可以利用这个方法传进你想要的参数,不过记住,这些参数必须被声明为final。
将匿名内部类改造成有名字的局部内部类,这样它就可以拥有构造函数了。
在这个匿名内部类中使用初始化代码块。
为什么需要内部类?
java内部类有什么好处?为什么需要内部类?
首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。
不过你可能要质疑,更改一下方法的不就行了吗?
的确,以此作为设计内部类的理由,实在没有说服力。
真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题 没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java内部类的作用分析 的相关文章

  • Code::Blocks使用教程

    使用之前我们先准备一段代码 include lt stdio h gt include lt stdlib h gt int main printf 34 欢迎进入www dotcpp com编程网站 xff01 34 system 34
  • magento中在.htaccess设置website code

    在 htaccess中 xff0c 添加以下的内容 xff1a SetEnvIf Host www newjueqi com MAGE RUN CODE 61 newjueqi SetEnvIf Host www newjueqi com
  • QT DirectShowPlayerService::doSetUrlSource: Unresolved error code 0x800c000d ()

    使用QT播放音频的时候出现如下错误 DirectShowPlayerService doSetUrlSource Unresolved error code 0x800c000d 原因是url错误
  • opencv模板匹配步骤及Code

    opencv模板匹配步骤及Code 首先介绍一下模板匹配的适用场景 xff1a 1 图像检索 2 目标跟踪 简单的说 xff0c 模板匹配最主要的功能就是在一幅图像中去寻找和另一幅模板图像中相似度最高的部分 xff0c 这就是模板匹配 比如
  • Received status code 400 from server: Bad Request

    一 报错信息 FAILURE span class token operator span span class token class name Build span failed span class token keyword wit
  • Window下LaTex+VS Code的配置

    目录 前言 一 软件下载二 软件安装1 TexLive安装2 VS Code及插件安装 三 配置 VS Code四 简单测试一下五 进阶操作及可能遇到的问题1 前向搜索和反向搜索2 编译带参考文献的 tex文件 前言 考虑本文受众有新手小白
  • Error executing aapt: Return code -1073741819

    总会有让人喷血的事情勾起写博客的欲望 xff0c 希望能坚持 折腾了两天的是个小问题 xff0c 就是标题上的Error executing aapt Return code 1073741819 解决的方法也很简单参考1中所述 xff0c
  • Attitude Control (Copter Code Overview)

    Attitude Control Copter Code Overview Between AC3 1 5 and AC 3 2 the attitude control logic was restructured as part of
  • VS Code Remote SSH远程连接异常:Resolver error: Error: Running the contributed command

    VS Code Remote SSH远程连接异常 问题描述原因分析解决方案扩展Remote SSH首次连接插件做了什么Remote SSH对于远程Linux的要求 问题描述 通过VS Code插件Remote SSH连接一台新主机时 xff
  • 802.11标准deauth报文的reason code中文版

    代码 原因 0 保留 1非特定原因 2以前的身份验证不再有效 3由于发送STA离开 xff08 或已经离开 xff09 ibs或ESS而被取消身份验证 4由于不活动而解除关联 5已解除关联 xff0c 因为AP无法处理所有当前关联的STA
  • Visual Studio Code语言设置为中文

    1 Visual Studio Code下载安装 https code visualstudio com 2 语言设置 2 1 快捷键 Windows Linux 快捷键是 xff1a ctrl 43 shift 43 p macOS 快捷
  • python解析DataMatrix Code二维码

    span class token comment 安装 span span class token triple quoted string string 39 39 39 sudo apt get install libdmtx0a pi
  • Ubuntu 16.04下安装visual studio code

    一 坑和解决办法 很多帖子上写的方法都是使用命令方式 xff1a 1 先安装make sudo add apt repository ppa ubuntu desktop ubuntu make sudo apt get update su
  • visual studio code中模拟浏览器端向服务端发起请求

    一 需要使用的插件 二 使用方式 1 创建 http文件 2 在所创建的 http文件中输入如下内容 相关具体的使用方式可参见 xff1a https marketplace visualstudio com items itemName
  • opencv_tutorial_code学习——canny边缘检测后findContours

    tutorial code ShapeDescriptors findContours demo cpp 步骤 xff1a 1 灰度化 2 滤波 3 canny边缘检测 4 findContours canny output contour
  • 使用VS Code连接远程服务器

    目录 一 VS Code的安装与下载 二 安装插件 三 添加服务器连接配置 四 连接服务器 一 VS Code的安装与下载 关于VS Code的安装与下载及VS Code的使用方式详见如下链接 VSCode安装教程并配置C C 43 43
  • java内部类的作用分析

    提起Java内部类 Inner Class 可能很多人不太熟悉 实际上类似的概念在C 里也有 那就是嵌套类 Nested Class 关于这两者的区别与联系 在下文中会有对比 内部类从表面上看 就是在类中又定义了一个类 下文会看到 内部类可
  • Transformer代码讲解(最最最最......详细)

    Transformer代码讲解 最最最最 详细 整个代码主要分为两部分去讲解 一 完整代码 二 部分代码剖析 1 主函数if name main 2 从整体网路结构来看 分为三个部分 编码层 解码层 输出层 3 Encoder 部分包含三个
  • Golang实现一个事务型内存数据库

    内存数据库经我们经常用到 例如Redis 那么如何从零实现一个内存数据库呢 本文旨在介绍如何使用Golang编写一个KV内存数据库MossDB 特性 MossDB是一个纯Golang编写 可嵌入的 键值型内存数据库 包含以下特性 可持久化
  • Java字节流与字符流的区别

    字节流与和字符流的使用非常相似 两者除了操作代码上的不同之外 是否还有其他的不同呢 实际上字节流在操作时本身不会用到缓冲区 内存 是文件本身直接操作的 而字符流在操作时使用了缓冲区 通过缓冲区再操作文件 如图12 6所示 下面以两个写文件的

随机推荐

  • python题库刷题训练软件

    刷题软件 文末有联系方式 注明来意 1 下列叙述中正确的是 A 数据库系统减少了数据冗余 B 经规范化后的数据库系统避免了一切冗余 C 数据库系统中数据的一致性是指数据类型一致 D 数据库系统比文件系统能管理更多的数据 数据库系统的数据具有
  • O(logN)求斐波那契数列第N项:动态规划、矩阵分治

    logN求Fibonacci数列第N项 斐波那契数列通项公式 F i F i
  • 解决skia静态库中关于jpeg/png编码解码器的全局变量的问题

    近期在研究Andriod的图形渲染系统skia 编译好skia后 写了一个小小的测试程序 include SkBitmap h include SkDevice h include SkPaint h include gm h includ
  • 循环神经网络--01 序列模型

    生成数据 import torch from torch import nn from d2l import torch as d2l T 1000 time torch arange 1 T 1 dtype torch float32 x
  • priority_queue优先队列的使用方法

    说到优先队列 大家肯定想到了队列 这肯定是对于学过队列的同学来说 当然了 没学过也没事 对于本篇文章没什么问题滴 队列的特征是后进后出 按照排队先来后到的顺序的 本篇文章介绍的priority queue优先队列是按照优先级的顺序来排队 优
  • JAVA开发环境配置指南

    进入Java世界之前 我们需要铺一条 路 才能通往Java的世界并且尽情遨游 那么这条 路 是什么呢 是的 就是Java的开发环境 今天我们一起来学习Java开发环境的配置 1 下载与安装Java JDK 首先 我们需要从Oracle官网下
  • Leetcode-257 二叉树的所有路径(深搜)

    给你一个二叉树的根节点 root 按 任意顺序 返回所有从根节点到叶子节点的路径 叶子节点 是指没有子节点的节点 输入 root 1 2 3 null 5 输出 1 gt 2 gt 5 1 gt 3 示例 2 输入 root 1 输出 1
  • SAP ABAP HANA 使用ECLIPSE而不是HANA Studio

    首先是ECLIPSE下载 链接 在这个网页中找到SAP HANA Tools这一块 然后跟着procedure的操作来做 即下图 安装完成后 连接SAP系统 打开Eclipse 点图中的按钮或菜单栏Windows gt Perspectiv
  • 创建SpringBoot + Druid + Mybatis项目

    本章目录 前言 一 搭建SpringBoot框架 二 配置druid连接池 1 选择原因 2 druid参数 3 druid的配置 三 Mybatis持久层 1 三层架构 2 选择原因 3 mybatis配置 本章将讲述如何创建spring
  • 机器视觉检测系统完整解决方案以及开发流程

    点击上方 小白学视觉 选择加 星标 或 置顶 重磅干货 第一时间送达 第一步是确定要求并确定是否可行 机器视觉一词可以想象是具有一组眼睛的计算机进行检测或检验行为 为了开发机器视觉应用的完整解决方案 视觉工程师执行一系列通常分为五个类别的任
  • unity消息机制实现

    在mvc模式中 消息机制被广泛使用 Unity3d自带的消息机制真心不好用 像SendMessage 需要知道响应事件的物件 还需要一个响应函数的函数名字符串作为参数 如果我们有多个物件都要响应某个事件怎么办呢 或者我们不知道有哪些物件要响
  • MySQL-数据库读写分离(下)

    作者 小刘在C站 个人主页 小刘主页 努力不一定有回报 但一定会有收获加油 一起努力 共赴美好人生 学习两年总结出的运维经验 以及思科模拟器全套网络实验教程 专栏 云计算技术 小刘私信可以随便问 只要会绝不吝啬 感谢CSDN让你我相遇 前言
  • js为浏览器URL追加参数

    setTimeout gt let newurl updateQueryStringParameter window location href id 123456 向当前url添加参数 没有历史记录 window history repl
  • SpringBoot笔记:SpringBoot启动参数配置

    文章目录 目的 测试代码 配置文件配置 获取自定义参数 项目打包发布 修改启动配置 方式一 系统变量 方式二 命令行参数 springboot启动参数解释 目的 1 熟悉springboot多环境配置 2 熟悉springboot使用jar
  • Webpack源码分析-打包后的文件分析

    Webpack源码解析 使用webpack版本 html webpack plugin 4 5 0 webpack 4 44 2 webpack cli 3 3 12 打包后文件分析 webpack code dist bundle js
  • UTM安全功能部署场景——web过滤原理、url过滤

    目录 web过滤原理 网络过滤检查模式 代理模式 流模式 DNS模式 应用场景 一 组网需求 二 组网拓扑 三 配置要点 四 配置步骤 五 配置步骤 web过滤原理 网络过滤检查模式 代理模式 基于代理的检查包括流量缓冲和在决定一个行动之前
  • CSS里的style标签内为什么要加html注释符

    今天俺终于搞懂了 CSS里的style标签内为什么要加html注释符 说来惭愧啊 搞开发也有那么点时间了吧 经常看在style标签里含有这个html的注释符号 想去搞懂原因 还真没找着 上网没找到原因 可能是自己查找的方式不对吧 下面步入正
  • 【202211】国内镜像源地址

    Ubuntu Python Nodejs MySQL Git Chromium Docker Homebrew 等一系列的常用最推荐的镜像源 清华源镜像清华大学开源软件镜像站 Tsinghua Open Source Mirror 可能是最
  • anguar12里面FormControl学习

    在Angular 12中 要动态修改FormGroup 你可以使用patchValue 方法或setValue 方法 使用patchValue 方法 import Component OnInit from angular core imp
  • java内部类的作用分析

    提起Java内部类 Inner Class 可能很多人不太熟悉 实际上类似的概念在C 里也有 那就是嵌套类 Nested Class 关于这两者的区别与联系 在下文中会有对比 内部类从表面上看 就是在类中又定义了一个类 下文会看到 内部类可