【Java中级】10章、内部类、局部内部类、匿名内部类、成员内部类、静态内部类的基本语法和细节讲解配套例题巩固理解【5】

❤️ 【内部类】干货满满,本章内容有点难理解,需要明白类的实例化,学完本篇文章你会对内部类有个清晰的认知
💕 内容涉及内部类的介绍、局部内部类匿名内部类(重点)、成员内部类静态内部类
🌈 跟着B站一位老师学习的内部类内容,先写这篇文章为学习内部类的小伙伴提供思路支持,希望可以一起感受java的魅力,爱上java编程!!!


文章目录

  • 1、内部类
    • 1.1、快速入门
    • 1.2、内部类的分类
      • 1.2.1、局部内部类的使用
    • 1.3、匿名内部类!!!!
    • 1.4、匿名内部类-最佳实践
    • 1.5、成员内部类
      • 作用域
    • 1.6、静态内部类
    • 1.7、小结
    • 1.8、一道小小题
  • 共勉

1、内部类

内部类基本介绍:一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员。
其中类的五大成员为:变量、方法、构造器、代码块和内部类

内部类的最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系

在这里插入图片描述
在这里插入图片描述

1.1、快速入门

了解内部类的结构

  • 外部类Outer中内嵌一个内部类Inner
package com.fhsedu.innerclass;public class InnerClass01 {//外部其他类public static void main(String[] args) {}
}
class Outer{//外部类private int n1 = 100;//属性public Outer(int n1) {this.n1 = n1;}{//代码块System.out.println("代码块...");}class Inner{//内部类,在Outer类的内部}
}

1.2、内部类的分类

  • 匿名内部类—>重点!!!!

1.2.1、局部内部类的使用

package com.fhsedu.innerclass;public class LocalInnerClass {public static void main(String[] args) {Outer02 outer02 = new Outer02();outer02.m1();}
}
class Outer02{//外部类private int n1 = 100;private void m2() {System.out.println("this is outer02 m2()");}//私有方法public void m1() {//方法//1、局部内部类是定义在外部类的局部位置,通常在方法//3、不能添加访问修饰符,但是可以使用final 修饰//4、作用域:仅仅在定义它的方法或代码中final class Inner02{//局部内部类(本质任然是一个类)//2、可以直接访问外部类的所有成员,包括私有的public void f1() {//5、局部内部类可以直接访问外部类的成员、比如下面 外部类属性n1 和 方法m2()System.out.println("n1 = " + n1);m2();}}//6、外部类在方法中,可以创建Inner02对象,然后调用方法即可Inner02 inner02 = new Inner02();inner02.f1();/*class Inner03 extends Inner02{}*///可以的}
}


记住:

  1. 局部内部类定义在方法中/代码块
  2. 作用域在方法体或者代码块中
  3. 本质仍然是一个类
  1. 外部其他类----> 不能访问局部内部类(因为 局部内部类地位是一个局部变量,就好像private修饰的属性只能提供共有的get方法才能访问)
  2. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类命.this.成员)去访问

System.out.println("外部类的n2=" + 外部类命.this.n2);

代码演示获取Outer的属性:


class Outer02 {//外部类private int n1 = 100;public void m1() {//方法final class Inner02 {//局部内部类(本质任然是一个类)//2、可以直接访问外部类的所有成员,包括私有的private int n1 = 800;public void f1() {//   如果想访问外部类的成员,则可以使用(外部类命.this.成员)去访问//  解读: Outer02.this 本质就是外部类的对象,即:哪个对象调用了m1,Outer02就是哪个对象System.out.println("n1 = " + n1 + "外部类属性=" + Outer02.this.n1);System.out.println("Outer02.this 的 Hashcode=" + Outer02.this.hashCode());}}}
}

在这里插入图片描述

1.3、匿名内部类!!!!

Anonymous:匿名的

思考一个小问题:为什么java接口不能被实例化?

Java中的接口不能被实例化
这是因为接口是一种抽象类型,它定义了一组方法的签名,但不包含任何方法的实现。接口的主要目的是规定类应该实现哪些方法,而不是提供一个具体的实现。因此,接口本身并不能被实例化,也就是说不能使用
new关键字来实例化一个接口。接口只能被类实现,并且类必须实现接口中定义的所有方法。然后通过类的实例来调用接口中定义的方法。


接口IA:定义了一个抽象方法cry()

interface IA{void cry();
}

定义一个主类

public class AnonymousInnerClass {public static void main(String[] args) {Outer04 outer04 = new Outer04();outer04.method();}
}

外部类和匿名内部类

class Outer04{//内部类private int n1 = 10;//属性public void method() {//方法//基于接口的匿名内部类//匿名内部类使用一次,就不能再使用//  即不能  new tiger$1()IA tiger = new IA(){@Overridepublic  void cry() {System.out.println("老虎...");}};tiger.cry();IA dog = new IA(){@Overridepublic void cry() {System.out.println("小狗...");}};dog.cry();//打印两个匿名内部类的类类型//dog的运行类型:class com.fhsedu.Outer04$1System.out.println("dog的运行类型:" + dog.getClass());//cat的运行类型:class com.fhsedu.Outer04$2System.out.println("cat的运行类型:" + cat.getClass());}
}

小结:

匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
一般语法:

new  类或接口(参数列表){类体;
};

小结:

  1. 本质是类,内部类
  2. 该类没有名字,同时还是一个对象
  3. 可以直接访问外部类的所有成员,包括私有的
  4. 不能添加访问修饰符,因为它的地位就是一个局部变量。
  5. 作用域:仅仅在定义它的方法或代码块中。
  6. 匿名内部类—>访问---->外部类成员【访问方式:直接访问或外部类名.this.属性
  7. 外部其他类---->不能访问---->匿名内部类【因为匿名内部类地位就是一个局部变量】
  8. 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)去访问

1.4、匿名内部类-最佳实践

Exercise01

package com.fhsedu.innerclass;public class AnonymousInnerClassExercise01 {public static void main(String[] args) {f1(new IL() {@Overridepublic void show() {System.out.println("this is a picture!!!");}});//传统方法f1(new Picture());}//静态方法,形参是接口类型public static void f1(IL il) {il.show();}
}
//接口
interface IL {void show();
}
//传统方法-》类实现IL-》编程领域(硬编码)
class Picture implements IL {@Overridepublic void show() {System.out.println("this is a picture!");}
}

在这里插入图片描述


在这里插入图片描述

自己可以先思考一下实现思想,重要的是培养编程思维

代码实现

  • 接口
//定义一个接口
interface Bell{//默认抽象方法void ring();
}
//定义一个类
class Cellphone{//参数是Bellpublic void alarmClock(Bell bell){bell.ring();}
}
  • 实现类
public class homework02 {public static void main(String[] args) {//创建一个对象,并调用它里面的alarmClock(..)方法,//  进行传入一个匿名内部类new Cellphone().alarmClock(new Bell() {@Overridepublic void ring() {System.out.println(this.getClass());System.out.println("小伙伴,别熬夜了!");}});//跟上面一样new Cellphone().alarmClock(new Bell() {@Overridepublic void ring() {System.out.println(this.getClass());System.out.println("明天吃火锅!");}});}
}

在这里插入图片描述
(这里我把接口也打印出来了,复习一下接口的名字)

  • 如果有两个类:类1 和 类2 都有匿名内部类,那么分别为各自的类起名字(Java内部)如:类1种的匿名内部类为 Outer$1、Outer$2 此时下面的为:Inner$1、Inner$2。。。
  • 匿名内部类中编译类型是赋予的,运行类型是系统给的

1.5、成员内部类

说明:成员内部是定义在外部类的成员位置,并且没有static修饰

  1. 可以直接访问外部类的所有成员
  2. 可以添加访问修饰符(public、protected、默认、private),因为它的地位就是一个成员

代码演示

package com.fhsedu.innerclass;public class MemberInnerClass01 {public static void main(String[] args) {Outer08 outer08 = new Outer08();outer08.t1();}
}
class Outer08 {//外部类private int n1 = 10;public String name = "张三";class Inner08{//成员内部类public void say() {//成员内部类可以访问所有外部类的成员、包含私有的System.out.println("Outer08 的 n1 =" +Outer08.this.n1 + "Outer08 的 name = " + Outer08.this.name);}}public void t1() {Inner08 inner08 = new Inner08();inner08.say();}
}

成员内部类的使用:在外部类创建方法创建对象调用方法
在这里插入图片描述


作用域

作用于和外部类的其他成员一样,为整个类体
比如之前我们在外部类的成员方法中创建成员内部类对象,再调用对象

  • 外部其他类访问内部类
package com.fhsedu.innerclass;public class MemberInnerClass01 {public static void main(String[] args) {//外部类自己的方法直接调用Outer08 outer08 = new Outer08();outer08.t1();//外部其他类,使用成员内部类的三种方式//new Inner08();错误方法//第一种语法,不要特别的纠结//Outer08.new Inner08()Outer08.Inner08 inner08 = outer08.new Inner08();inner08.say();//第二种方法://在外部类中创建一个方法用于返回匿名内部类Outer08.Inner08 inner08Instance = outer08.getInner08();inner08Instance.say();}
}
class Outer08 {//外部类private int n1 = 10;public String name = "张三";protected class Inner08{//成员内部类  //可以使用访问修饰符public void say() {//成员内部类可以访问所有外部类的成员、包含私有的System.out.println("Outer08 的 n1 =" +Outer08.this.n1 + "Outer08 的 name = " + Outer08.this.name);}}public Inner08 getInner08() {return new Inner08();}public void t1() {Inner08 inner08 = new Inner08();inner08.say();}
}

重要的事情说三遍!!!
如果外部类和内部类成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。

代码演示

(看高亮块)

1.6、静态内部类

  • 静态类只能访问静态成员


  1. 静态内部类—>访问—>外部类(静态属性)【访问方式:直接访问所有静态成员】
  2. 外部类—>访问—>静态内部类 访问方式:创建对象,再访问

外部其他类访问静态内部类:

  • 外部类访问静态内部类,跟之前的不一样


外部类&&内部类

class Outer10 {private int n1 = 10;private static String name = "张三";private static void cry() {System.out.println("cry静态成员方法");}//Inner10就是静态内部类//1、放在外部类的成员位置//2、使用static 修饰//3、可以直接访问外部类的所有静态成员包括私有的,但不能直接访问非静态成员//4、可以添加任意访问修饰符(public、protected、默认、private)因为它的地位就是一个成员static class Inner10 {public void say() {cry();System.out.println(name);}}public void m1() {Inner10 inner10 = new Inner10();inner10.say();}public Inner10 getInner10() {//非静态的可以访问静态和非静态return new Inner10();}public static Inner10 getInner10_() {//静态只能访问静态return new Inner10();}}

测试类

public class StaticInnerClass01 {public static void main(String[] args) {Outer10 outer10 = new Outer10();outer10.m1();//外部其他类 使用静态内部类//方式1//因为静态内部类,是可以通过哦类命直接访问(前提是满足访问权限)Outer10.Inner10 inner10 = new Outer10.Inner10();inner10.say();//方式2Outer10.Inner10 inner101 = outer10.getInner10();inner101.say();Outer10.Inner10 inner10_ = Outer10.getInner10_();//访问静态的inner10_.say();}
}

注意细节点
在这里插入图片描述


7.如果外部类和静态内部类的成员重名时,静态内部类(之前是局部内部类和匿名内部类)访问时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员) 去访问

  • 此时不用加this了,因为访问的是静态的

在这里插入图片描述

1.7、小结

小结:

  1. 内部类有四种 局部内部类,匿名内部类,成员内部类,静态内部类
  2. 重点还是掌握 匿名内部类使用
    1. new 类/接口(参数列表){ //… }
  3. 成员内部类,静态内部类 是放在外部类的成员位置,本质就是一个成员
  4. 其他细节:看笔记…

1.8、一道小小题

在这里插入图片描述

分别指向不同的对象空间:答案:5,5

package com.fhsedu;public class Test_ {public Test_() {Inner s1 = new Inner();s1.a = 10;Inner s2 = new Inner();System.out.println(s2.a);}class Inner {public int a = 5;}public static void main(String[] args) {Test_ t = new Test_();//5Inner r = t.new Inner();System.out.println(r.a);//5}
}

共勉

整理心情,再次出发!!!
老黄牛精神,持之以恒坚持
在这里插入图片描述

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

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

相关文章

内容中台:驱动多渠道营销的关键策略

在数字营销快速发展的今天,企业需要在多个渠道(网站、社交媒体、移动应用等)上同步管理内容。尽管网站仍是品牌展示的核心,但信息分散、多平台重复创建内容的问题,让营销人员面临巨大的管理挑战。 内容中台&#xff0…

SvelteKit 最新中文文档教程(17)—— 仅服务端模块和快照

前言 Svelte,一个语法简洁、入门容易,面向未来的前端框架。 从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1: Svelte …

CMake 中的置变量

在 CMake 中,变量是存储和传递信息的重要方式。以下是一些常用的 CMake 变量,以表格形式列出,包括它们的名称、含义和常见用途: 变量名称含义常见用途CMAKE_CURRENT_SOURCE_DIR当前处理的 CMakeLists.txt 文件所在的源代码目录的…

深入解析C++类:面向对象编程的核心基石

一、类的本质与核心概念 1.1 类的基本定义 类是将**数据(属性)与操作(方法)**封装在一起的用户自定义类型,是面向对象编程的核心单元。 // 基础类示例 class BankAccount { private: // 访问控制string owner; …

介绍 Docker 的基本概念和优势,以及在应用程序开发中的实际应用及数组讲解

Docker 是一种轻量级的容器化技术,能够让开发者将应用程序和其所有依赖项打包成一个独立的容器,实现快速部署和运行。以下是 Docker 的基本概念和优势: 基本概念: 镜像(Image):镜像是一个只读的…

在msys2里面的mingw64下面编译quickjs

其实非常的简单,就是正常的make 和make install就行了,这里只是简单的做个编译过程记录。 打开开始--程序--里面的msys64里面的mingw64控制台窗口,切换到quickjs下载解压缩后的目录,执行make和make install ndyHP66G5 MINGW64 ~…

el-table实现表头带筛选功能,并支持分页查询

最开始尝试了下面方法,发现这种方法仅支持筛选当前页的数据,不符合产品要求 于是通过查询资料发现可以结合filter-change事件,当表格的筛选条件发生变化的时候会触发该事件,调接口获取符合条件的数据,实现如下 1、表格…

OpenCV 从入门到精通(day_03)

1. ROI切割 ROI:Region of Interest,翻译过来就是感兴趣的区域。什么意思呢?比如对于一个人的照片,假如我们要检测眼睛,因为眼睛肯定在脸上,所以我们感兴趣的只有脸这部分,其他都不care&#xf…

OpenGL进阶系列20 - OpenGL SuperBible - bindlesstex 例子学习

目录 一:概述: 二:相关API介绍 三:代码完整注释 一: 概述: 什么是无绑定纹理(bindless texture)?无绑定纹理是OpenGL的一项技术,旨在消除传统的纹理绑定操作。这项技术允许着色器直接访问纹理而不需要显式地将纹理绑定到某个纹理单元,从而减少了渲染管线中的开销…

Spring Security认证授权深度解析

一 Spring Security简介 Spring Security是Spring生态系统中的一个安全框架,主要用于处理认证(Authentication)和授权(Authorization)。它提供了一套完整的安全解决方案,可以轻松集成到Spring应用中。 二 核心概念 1. 认证(Authentication) 验证用户…

[学成在线]10-课程审核

课程审核 需求分析 根据模块需求分析,课程发布前要先审核,审核通过方可发布。下图是课程审核及发布的流程图: 为什么课程审核通过才可以发布呢? 这样做为了防止课程信息有违规情况,课程信息不完善对网站用户体验也不…

【SpringBoot + MyBatis + MySQL + Thymeleaf 的使用】

目录: 一:创建项目二:修改目录三:添加配置四:创建数据表五:创建实体类六:创建数据接口七:编写xml文件八:单元测试九:编写服务层十:编写控制层十一…

Elasticsearch索引的字段映射

目录 type String类型 text和keyword的区别 数值类型 日期类型 index doc_values fields analyzer store index_options ElasticSearch索引映射示例 Elasticsearch中的字段设置直接影响数据的存储、索引和查询行为。结合索引查询场景合理设置mapping信息可以起到提…

【已解决】实际参数列表和形式参数列表长度不同、java: 无法将类xxx中的构造器xxx应用到给定类型| lombok相关

idea运行maven项目时&#xff0c;报错这个&#xff08;如标题&#xff09; 解决方案记录&#xff1a; 找到了之前的、能运行成功不报错的 maven项目。参考其pom.xml文件中lombok相关部分&#xff0c;将<path>标签下的lombok加个版本号&#xff0c;就运行成功了&#xff1…

4. 学习网站:学习新的技能或培养兴趣爱好

文章目录 前言英文网站&#xff1a;培养兴趣爱好的应用总结 前言 学习网站以及具体提供的内容。 英文网站&#xff1a; Coursera&#xff1a;提供来自全球顶尖大学和机构的在线课程&#xff0c;涵盖广泛的学科&#xff0c;包括编程、数据科学、商业和艺术等。Udemy&#xff1…

LabVIEW 开发中 TCP 与 UDP 协议的差异

在 LabVIEW 开发的网络通信场景中&#xff0c;TCP 和 UDP 是常用的两种传输层协议&#xff0c;它们各自具有独特的特点&#xff0c;适用于不同的应用需求。理解它们之间的差异&#xff0c;有助于开发者根据具体项目需求选择合适的协议&#xff0c;以实现高效、稳定的网络通信。…

04-深入解析 Spring 事务管理原理及源码

深入解析 Spring 事务管理原理及源码 Spring 事务管理&#xff08;Transaction Management&#xff09;是企业级应用开发中至关重要的功能之一&#xff0c;它确保数据操作的 原子性、一致性、隔离性、持久性&#xff08;ACID&#xff09;。 本篇博客将从 Spring 事务的基本概…

【Linux】用户向硬件寄存器写入值过程理解

思考一下&#xff0c;当我们咋用户态向寄存器写入一个值&#xff0c;这个过程是怎么样的呢&#xff1f;以下是应用程序通过标准库函数&#xff08;如 write()、ioctl() 或 mmap()&#xff09;向硬件寄存器写入值的详细过程&#xff0c;从用户空间到内核再到硬件的完整流程&…

自动驾驶02:点云预处理——02(运动补偿篇LIO-SAM)

当激光雷达&#xff08;LiDAR&#xff09;在运动中采集点云时&#xff0c;每个点的时间戳不同&#xff0c;而车辆在移动&#xff0c;导致点云在不同时间点的坐标与实际情况不符&#xff0c;这种现象称为运动畸变&#xff08;Motion Distortion&#xff09;。为了得到无畸变的点…

基础算法篇(3)(蓝桥杯常考点)—图论

前言 这期是基础算法篇的第三节&#xff0c;其中的dijkstra算法更是蓝桥杯中的高频考点 图的基本相关概念 有向图和无向图 自环和重边 稠密图和稀疏图 对于不带权的图&#xff0c;一条路径的路径长度是指该路径上各边权值的总和 对于带权的图&#xff0c;一条路径长度时指该路…