【Java 学习】:内部类详解

详谈Java内部类

📃📃本文将通过Java内部类 是什么,为什么被广泛使用,以及又该如何去使用这三个方面来详细讲解其相关知识。

文章目录

1. 内部类是什么

2. 为什么要使用内部类

3. 如何使用内部类

🍉成员内部类

🥑静态内部类

🥝局部内部类

🍋‍🟩匿名内部类

📖总结


1. 内部类是什么

🥬🥬🥬当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。

/**
* 外部类
*/
public class Outer {//.../*** 内部类*/class Inner {//...}
}

注:

  • 我们一般将内部类分为四种:成员内部类静态内部类局部(方法内部类)匿名内部类
  • 外部类的定义是相对于内部类而言的

2. 为什么要使用内部类

🍈使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。——《Think in java》

🍈也就是说内部类拥有类的基本特征。(eg:可以继承父类,实现接口)在实际问题中我们会遇到一些接口无法解决或难以解决的问题,此时我们可以使用内部类继承某个具体的或抽象的类,间接解决类无法多继承引起的一系列问题。

注:内部类可以嵌套内部类,但是这极大的破坏了代码的结构,但是这里不推荐使用。

举个例子🌰

/**1. OuterClass类继承了 A,实现了IFunctionA
*/
public class OuterClass extends A implements IFunctionA{ /***	Inner类继承了 B,实现了IFunctionB*/class InnerClass extends B implements IfunctionB{//} 
}// 这里我要说明一下,一个源文件只能有一个 public 类,因此 InnerClass 不能用 public

除此之外,内部类还可以:

  1. 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
  2. 内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
  3. 内部类提供了更好的封装,除了该外围类,其他类都不能访问。
  4. 创建内部类对象的时刻并不依赖于外围类对象的创建。

3. 如何使用内部类

🍉成员内部类

 💢💢也叫作实例内部类,是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:

// 实例内部类
class OuterClass {public int data1 = 1;public static int data2 = 2;private int data3 = 3;/*成员方法*/public void OuterMethod() {System.out.println("外部类的outerMethod方法");}/*静态方法*/public static void OuterStaticMethod() {System.out.println("外部类的outerStaticMethod静态方法");}/*同名方法*/public void test() {System.out.println("OutClass:: test()");InnerClass innerClass = new InnerClass();}class InnerClass{public int data1 = 10;public int data4 = 4;//public static int data5 = 5; // jdk8 不支持这样用,jdk17 支持public static final int data5 = 5;private int data6 = 6;public void InnerShow() {//访问内部类属性System.out.println("data4:" + data4);//内部类访问外部属性System.out.println("data3:" + data3); //私有权限的外部类也可以访问//当和外部类冲突时,直接引用属性名,是内部类的成员属性System.out.println("data1:" + this.data1); // 默认为this//当和外部类属性名重叠时,可通过外部类名.this.属性名System.out.println("data1:" + OuterClass.this.data1); //访问外部类成员// 访问外部类方法OuterMethod();OuterStaticMethod();}public void test(){System.out.println("InnerClass:: test()");}}/* 	外部类访问内部类信息 */public void OuterShow() {InnerClass inner = new InnerClass();inner.InnerShow();}
}public class Test {/*其他类使用成员内部类*/public static void main(String[] args) {//创造内部类对象,两种实例化方法OuterClass outer = new OuterClass(); //外部类对象OuterClass.InnerClass inner1 = outer.new InnerClass();OuterClass.InnerClass inner2 = new OuterClass().new InnerClass();inner1.test();inner1.InnerShow();}
}

运行结果如下:

注:成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。

总结:【抓住关键字——实例,作为实例成员存在】

  1. 内部类可以是任何的访问修饰符。由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰符。
  2. 内部类的内部不能有静态信息。
  3. 内部类也是类,该继承的继承、该重写的重写、该重载的重载,this和super随便用。
  4. 外部类访问内部类的信息,必须先实例化内部类,然后 . 访问。
  5. 内部类可以直接使用外部类的任何信息,如果属性或者方法发生冲突(重名),使用Outer.this.成员
  6. 其他类访问内部类:成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在外部类的对象。

🥑静态内部类

 💢💢Java中的静态内部类是指在一个类的内部定义的另一个类,并且该内部类被声明为静态(static)的。静态内部类与普通内部类的区别在于,静态内部类不依赖于外部类的实例,可以直接通过外部类名访问

// 静态内部类
class Outer{public int data1 = 1;/*外部类定义的属性(重名)*/public static int data2 = 2;public static int data3 = 3;static {System.out.println("外部类静态块");}/*成员方法*/public void outerMothod() {System.out.println("外部类的成员方法");}/*静态方法*/public static void outerStaticMethod() {System.out.println("外部类的静态方法");}public void test(){System.out.println("Out:: test()");}static class Inner{public int data4 = 4;public static int data5 = 5;public static int data3 = 33; //与外部类同名public void InnerShow(){// 访问内部类成员属性System.out.println("内部类data4:"+data4);//访问外部类成员属性//不重名访问 非静态成员属性//System.out.println(data1); //无法直接访问外部非静态成员System.out.println("data1:" + new Outer().data1); // 间接访问//不重名直接访问 静态成员属性System.out.println("外部类data2:" + data2);System.out.println("内部的data3:"+ data3);System.out.println("外部的data3:"+ Outer.data3);}public static void InnerStaticShow() {//调用时会先加载Outer类,类加载的时候执行静态代码块outerStaticMethod();}}/*外部类的内部如何和内部类打交道*/public static void callInner() {System.out.println(Inner.data3);//System.out.println(Inner.data4); //内部类的非静态成员属性无法直接访问System.out.println(new Inner().data4);Inner.InnerStaticShow();new Inner().InnerShow();  //调用内部类非静态成员方法}
}public class Test {/* 其他类访问静态内部类 */public static void main(String[] args) {//访问静态内部类的静态方法,Inner类被加载(类加载的时候执行静态代码块),此时外部类未被加载,独立存在,不依赖于外部类。Outer.Inner.InnerStaticShow();// 静态内部类实例化,不用(),相比于实例内部类优点:不需要外部类的引用Outer.Inner in = new Outer.Inner();in.InnerShow();}
}

总结:【抓住关键字——static,作为静态成员存在】

  1. 静态内部类可以包含任意的信息,可以被任意访问权限修饰符修饰。
  2. 静态内部类的方法只能访问外部类的static关联的成员。
  3. 静态内部类可以独立存在,不依赖于其他外围类。
  4. 其他类访问内部类的静态信息,直接 Outer.Inner.static成员信息 就可以了。
  5. 其他类实例化内部类 Outer.Inner instance = new Outer.Inner();,然后 instance. 成员信息(属性、方法)即可。

🥝局部内部类

💢💢 Java局部内部类是指在一个方法或代码块内部定义的内部类。与成员内部类不同,局部内部类只能在定义它的方法或代码块内部使用,无法在外部访问。

public class Out {/*属性和方法*/private int outVariable = 1;/*外部类定义的属性*/private int commonVariable = 2;/*静态的信息 */private static int outStaticVariable = 3;/*成员外部方法*/public void outerMethod() {System.out.println("我是外部类的outerMethod方法");}/*静态外部方法*/public static void outerStaticMethod() {System.out.println("我是外部类的outerStaticMethod静态方法");}/*成员方法,内部定义局部内部类*/public void outerCreatMethod(int value) {//public int a = 1; // 不行,局部内部类不能有访问权限修饰符//static int a = 1; // 也不能有static 修饰final int a = 1;int a1 = 1; // 默认为final/*女性*/boolean sex = false;//sex = true; // 有且仅有赋值一次/*局部内部类,类前不能有访问修饰符*/class In {private int inVariable = 10;private int commonVariable = 20;/*局部内部类方法*/public void InnerShow() {System.out.println("innerVariable:" + inVariable);//局部变量System.out.println("是否男性:" + sex);System.out.println("参数value:" + value);//调用外部类的信息System.out.println("outerVariable:" + outVariable);System.out.println("内部的commonVariable:" + commonVariable);System.out.println("外部的commonVariable:" + Out.this.commonVariable);System.out.println("outerStaticVariable:" + outStaticVariable);outerMethod();outerStaticMethod();}}//局部内部类只能在方法内使用In in = new In();in.InnerShow();}/* 开始程序 */public static void main(String[] args) {Out out = new Out();out.outerCreatMethod(100);}
}

总结:【抓住关键——作用域,作为方法的局部成员存在】

  1. 局部内部类不能有访问权限修饰符,无法创建静态信息。                                                局部内部类就像是方法里面的一个局部变量一样,是不能有访问权限修饰符和static修饰符的。
  2. 只能在方法内部使用。
  3. 可以直接访问方法内的局部变量和参数。【存在限制,需要 final 或有效的final修饰的】,但是不能更改。 
    ①直接被final修饰的变量。
    ②已被赋值且始终未改变的变量(有且仅有赋值一次),引用指向不能改变。注:JDK8以前(不包括8)只能访问被final修饰的变量。
  4. 编译器也有自己独立的字节码文件,命名格式:外部类名字$数字内部类名字.class

注:当局部内部类的变量修改时,就会产生如下错误:

Variable ‘xxx’ is accessed from within inner class, needs to be final or effectively final

传入局部内部类所在方法的参数同理,如果一直不变则可使用,反之则会报错。

局部内部类使用的很少,了解即可.

🍋‍🟩匿名内部类

 💢💢 Java匿名内部类是一种特殊的内部类,它没有类名,直接在创建对象时定义并实现。通常用于创建只需要使用一次的类对象,可以简化代码,提高代码的可读性和可维护性。

  • 原本我们需要创建子类或实现类,去继承父类或实现接口,才能重写其中的方法。但是有时候我们这样做了,然而子类和实现类却只使用了一次(定义了一个对象)。这个时候我们就可以使用匿名内部类,不用去写子类和实现类,起到简化代码的作用。
  • 这样做,把子类继承父类,重写父类中的方法,创建子类对象,合成了一步完成,减少了其中创建子类的过程。或者实现类实现接口,重写接口中的方法,创建实现类对象,合成了一步完成,减少了其中创建实现类的过程。

🥬匿名内部类是不能有名字的类,他们不能被引用,只能在创建是用 new 语句来声明他们。

// 匿名内部类
interface IA{void test(); //接口的方法不能有具体实现
}public class Test {public static void main(String[] args) {// 匿名内部类对象,下面两种方法都可以/*new IA(){@Overridepublic void test() {System.out.println("重写了接口的方法");}};*/IA a = new IA(){@Overridepublic void test() {System.out.println("重写了接口的方法");}};a.test();}
}

总结:【匿名内部类通常继承一个类或实现一个接口】

  1. 匿名内部类没有访问权限修饰符。
  2. 匿名内部类要实现父类或接口的所有抽象方法,其他方法可以根据自己的情况进行重写。
  3. 匿名内部类不应当添加自己的成员,因为匿名类没有类名无法向下转型,父类型的引用无法访问。
  4. 匿名内部类访问方法参数时也有和局部内部类同样的限制。
  5. 匿名内部类没有构造方法。
  6. 匿名类是表达式形式定义的,所以末尾以分号;来结束。


📖总结

具体来说,内部类信息(属性、方法)可以和外部类重名;内部类是具有类的基本特征的独立实体;可以利用访问修饰符隐藏内部类的实施细节,提供了更好的封装;静态内部类使用时可直接使用,不需先创造外部类。

💞 💞 💞那么本篇到此就结束,希望我的这篇博客可以给你提供有益的参考和启示,感谢大家支持!!!祝大家天天开心

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/491804.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何解决samba服务器共享文件夹不能粘贴文件

sudo vim /etc/samba/smb.conf在samba的配置文件中增加一个选项 writable yes重启Samba服务以使更改生效: sudo service smbd restart

PyTorch3D 可视化

PyTorch3D是非常好用的3D工具库。但是PyTorch3D对于可用于debug(例如调整cameras参数)的可视化工具并没有进行系统的介绍。这篇文章主要是想介绍我觉得非常使用的PyTorch3D可视化工具。 1. 新建一个Mesh 从hugging face上下载一个glb文件,例…

RabbitMQ的核心组件有哪些?

大家好,我是锋哥。今天分享关于【RabbitMQ的核心组件有哪些?】面试题。希望对大家有帮助; RabbitMQ的核心组件有哪些? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 RabbitMQ是一个开源的消息代理(Messag…

SM4笔记整理

文章目录 1. 介绍2. 算法定义3. 迭代运算3.1 轮函数F3.2 合成置换T 4. SM4秘钥生成4.1 具体步骤4.2 系统参数FK4.2 固定参数CK 5. 参考资料 以下内容为信息安全开发过程中,SM4对称加密算法的笔记。 对称加密算法汇总介绍:对称加密算法和模式 1. 介绍 …

如何使用Git or SVN--可视化工具

不会吧 现在还有人不会Git可视化工具 ,作为一个从命令行转为可视化的开发者,深知这个可视化工具的重要性,之前在命令行去维护我们的工程是一个很头疼的事情 ,后面也就有了可视化工具,市面上的工具的教程都不是很详细哥…

基于Clinical BERT的医疗知识图谱自动化构建方法,双层对比框架

基于Clinical BERT的医疗知识图谱自动化构建方法,双层对比框架 论文大纲理解1. 确认目标2. 目标-手段分析3. 实现步骤4. 金手指分析 全流程核心模式核心模式提取压缩后的系统描述核心创新点 数据分析第一步:数据收集第二步:规律挖掘第三步&am…

《Time Ghost》的制作:使用 DOTS ECS 制作更为复杂的大型环境

*基于 Unity 6 引擎制作的 demo 《Time Ghost》 开始《Time Ghost》项目时的目标之一是提升在 Unity 中构建大型户外环境的构建标准。为了实现这一目标,我们要有处理更为复杂的场景的能力、有足够的工具支持,同时它对引擎的核心图形、光照、后处理、渲染…

华为大数据_unittest单元测试框架解析与应用

一、引言 随着软件开发的复杂度日益增加,单元测试在软件质量保证体系中扮演着越来越重要的角色。unittest作为Python的标准单元测试框架,以其简单、易用和强大的特性,受到了广大开发者的青睐。本文旨在深入解析unittest框架的核心原理&#…

修改uniapp下拉刷新圆圈颜色

直接看图 修改前就是常规的绿色 自定义更符合我们的软件 直接说方法 修改 在App.vue的style样式里添加一行 .uni-page-refresh--refreshing .uni-page-refresh__path{stroke:#FF2442; }我是通过 不执行 uni.stopPullDownRefresh(); 下拉刷新 之后通过F12看出来的 希望可以帮…

大屏开源项目go-view二次开发3----象形柱图控件(C#)

环境搭建参考: 大屏开源项目go-view二次开发1----环境搭建(C#)-CSDN博客 要做的象形柱图控件最终效果如下图: 其实这个控件我前面的文章也介绍过,不过是用wpf做的,链接如下: wpf利用Microsoft.Web.WebView2显示html…

MAC虚拟机上安装WDA环境

MAC虚拟机上安装WDA环境 一、MAC虚拟机切换root权限二、macOS上安装xcode若你的macOS系统可以在appstore下载安装若你安装的macOS系统版本太低,无法在appstore上安装xcode 三、macOS上安装WebDriverAgent四、使用xcode配置WDA安装到手机上高版本系统支持 一、MAC虚拟…

解决 Git Permission denied 问题

前言 push项目时出现gitgithub.com: Permission denied (publickey). fatal: Could not read from remote repository.Please make sure you have the correct access rights and the repository exists.出现这个问题表示你在尝试将本地代码推送到GitHub时,没有提供…

【工具】linux matlab 的使用

问题1 - 复制图表 在使用linux matlab画图后,无法保存figure。 例如在windows下 但是在linux下并没有这个“Copy Figure”的选项。 这是因为 “ The Copy Figure option is not available on Linux systems. Use the programmatic alternative.” 解决方案&…

Oracle最佳实践-优化硬解析

前段时间参加oracle CAB,oracle高级服务部门做了一个数据库最佳实践的报告,其中就有一项就是解决未使用绑定变量但执行次数很多的SQL; 对于一个数据库来说如果不知道该如何优化,那么最简单最有效的优化就是减少硬解析,…

【开源免费】基于SpringBoot+Vue.JS在线竞拍系统(JAVA毕业设计)

本文项目编号 T 013 ,文末自助获取源码 \color{red}{T013,文末自助获取源码} T013,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

socket编程UDP-实现滑动窗口机制与累积确认GBN

在下面博客中,我介绍了利用UDP模拟TCP连接、按数据包发送文件的过程,并附上完整源码。 socket编程UDP-文件传输&模拟TCP建立连接脱离连接(进阶篇)_udp socket发送-CSDN博客 下面博客实现了停等机制。 socket编程UDP-实现停…

【现代服务端架构】传统服务器 对比 Serverless

在现代开发中,选择合适的架构是至关重要的。两种非常常见的架构模式分别是 传统服务器架构 和 Serverless。它们各有优缺点,适合不同的应用场景。今天,我就带大家一起对比这两种架构,看看它们的差异,并且帮助你选择最适…

概率论得学习和整理24:EXCEL的各种图形,统计图形

目录 0 EXCEL的各种图形,统计图形 1 统计图形 / 直方图 / 其实叫 频度图 hist最合适(用原始数据直接作图) 1.1 什么是频度图 1.2 如何创建频度图,一般是只选中1列数据(1个数组) 1.3 如何修改频度图的宽度 1.4 hist图的一个特…

【第三节】Git 基本操作指南

目录 前言 一、获取与创建项目 1.1 git init 1.2 git clone 二、基本快照操作 2.1 git add 2.2 git status 2.3 git diff 2.4 git commit 2.5 git reset HEAD 三、 文件管理 3.1 git rm 3.2 git mv 四、Git 文件状态 5.1 工作目录 5.2 暂存区 5.3 本地仓库 5…

el-table 多表头+跨行跨列案例

效果&#xff1a; 代码&#xff1a; index.vue <template><div class"my-table"><el-tablev-loading"table.loading":data"table.data"bordersize"mini":header-cell-style"headerCellStyle":span-method&qu…