当前位置: 首页 > news >正文

Java 内部类

文章目录

    • 1、初识内部类
    • 2、非静态内部类(实例内部类)
    • 3、静态内部类(重点)
    • 4、内部类的使用
    • 5、局部内部类
    • 6、匿名内部类

1、初识内部类

如果一个事物的内部包含另一个事物,那么这是一个类的内部包含另一个类。

例如:身体和心脏的关系,又如汽车和发动机的关系。

把 A 类定义在 B 类的内部,A——内部类(嵌套类),B——外部类(宿主类)。

内部类的特点

  • 内部类提供了更好的封装,把内部类隐藏在外部类之中,不允许同一个包下的其他类访问该内部类。
  • 内部类成员可以直接访问外部类的私有数据。
  • 匿名内部类适合那些仅需要一次使用的类。
  • 方法里定义的内部类称为局部内部类。
  • 内部类比外部类可以多使用三个修饰符:private、protected、static。
  • 非静态内部类不能拥有静态成员。

内部类的分类

  • 成员内部类
    • 非静态内部类
    • 静态内部类
  • 局部内部类
  • 匿名内部类

成员内部类可以看成外部类的成员,可以使用四个访问控制符

外部类仅可以使用两个访问控制符:公共访问权限、包访问权限

private:本类访问
省略不写:包访问
protected:子父类访问
public:公共访问

定义内部类语法格式

修饰符 class 外部类名称 {修饰符 class 内部类名称 {}
}

内用外:随意访问

外用内:使用内部类对象

2、非静态内部类(实例内部类)

Cow.java

// 外部类 奶牛
public class Cow {private double weigth;public void test() {CowLeg cowLeg = new CowLeg(10, "黑白相间");cowLeg.show();}public Cow() {}public Cow(double weigth) {this.weigth = weigth;}// 非静态内部类 奶牛的腿private class CowLeg {private double length;private String color;public CowLeg() {}public CowLeg(double length, String color) {this.length = length;this.color = color;}public void show() {System.out.println("本牛腿的颜色是:" + color + ", 长度是:" + length);System.out.println("奶牛重量为:" + weigth);}}
}

测试

public class Application {public static void main(String[] args) {Cow cow = new Cow(20);cow.test();}
}

在外部类里包含一个 test() 方法,该方法里创建了一个内部类对象,并调用该对象 show() 方法。

在外部类里使用非静态内部类时,与平时使用普通类并没有太大区别。

编译上面程序,生成了两个字节码文件,一个是 Cow.class,另一个是 Cow$CowLeg.class,前者是外部类 Cow 的 class 文件,后者是 CowLeg 的字节码文件。

成员内部类(静态内部类、非静态内部类)的字节码文件总是这种形式:OuterInner$InnerClass.class

在非静态内部类里可以直接访问外部类的私有成员,是因为在非静态内部类的对象里保存了一个它所寄生外部类对象的引用。

当调用非静态内部类的实例方法时,必须有一个非静态内部类的实例,非静态内部类实例必须寄生在外部类实例里。

在这里插入图片描述

非静态内部类对象中保留外部类对象的引用内存示意图

变量重名怎么访问?

当在非静态内部类的方法内访问某个变量时,查找的顺序是:

本方法所在的局部变量 > 内部类成员变量 > 外部类成员变量

如果外部类成员变量、内部类成员变量、局部变量重名,则可通过使用 this、外部类类名.this 作为限定来区分。

public class Outer {public static void main(String[] args) {new Outer().show();}private String name = "外部类成员变量";public void show(){new Inner().test();}class Inner{private String name = "内部类成员变量";public void test() {String name = "局部变量";System.out.println(name); // 局部变量System.out.println(this.name); // 内部类成员变量System.out.println(Outer.this.name); // 外部类成员变量}}
}

内部类访外部类,直接用;

外部类访内部类,须在外部类方法中显式定义内部类对象来访问

public class OuterClass {public static void main(String[] args) {OuterClass outer = new OuterClass();// 只创建了外部类对象,还未创建内部类对象outer.showInner();}private int outerProp = 20;private void showInner() {// 访问内部类实例变量,需要显示创建内部类对象InnerClass innerClass = new InnerClass();System.out.println(innerClass.innerProp);innerClass.showOuter();}private class InnerClass {private int innerProp = 10;public void showOuter() {// 非静态内部类直接访问外部类成员System.out.println(outerProp);}}
}

非静态内部类对象和外部类对象的关系是什么样?

非静态内部类对象有则外部类对象一定有

外部类对象有但非静态内部类对象不一定有

1、不允许在外部类的静态成员中直接使用非静态内部类

public class A {class B {}public static void main(String[] args) {// 静态内容不能访问非静态内容。// 此处报错// new B();}
}

2、不允许在非静态内部类中定义静态成员

public class A {// 非静态内部类class B {// 都报错static int a;static void print(){}static {}}
}

非静态内部类里不能有静态方法、静态成员变量、静态代码块。

非静态内部类可以有实例代码块,作用与外部类实例代码块作用相同。

3、静态内部类(重点)

static 关键字的作用:把类的成员变成类相关,而不是实例相关。

static 关键字可以修饰内部类,但不可修饰外部类。

使用 static 修饰的内部类称为:静态内部类(类内部类)

静态内部类属于外部类本身,不属于外部类的某个对象。

静态内部类可以包含:静态成员、非静态成员。

根据静态成员不能访问非静态成员的规则:静态内部类里不能访问外部类的实例成员,只能访问外部类的类成员。

即使静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。

public class Demo01 {private int a1 = 10;private static int a2 = 20;private static class StaticInnerClass {private static int a3 = 30;public static void show() {// 访问外部类非静态成员报错// System.out.println(a1);System.out.println(a2);System.out.println(a3);}}
}

为什么静态内部类的实例方法也不能访问外部类的实例变量?

因为静态内部类是外部类的类相关的,而不是外部类的对象相关的。

也就是说:静态内部类对象不是寄生在外部类的实例中,而是寄生在外部类的类本身中。

当静态内部类对象存在时,并不存在一个被它寄生的外部类对象,静态内部类对象只持有外部类的类引用,没有持有外部类对象的引用。

如果允许静态内部类的实例方法访问外部类的实例成员,但找不到被寄生的外部类对象,会引起错误。

外部类不能直接访问静态内部类的成员但可以使用 静态内部类的类名.xxx 来访问类成员;

创建一个静态内部类对象来访问实例成员。

public class A {public static void main(String[] args) {new A().show();}static class B{private static int a1 = 10;private int a2 = 20;}public void show(){System.out.println(B.a1);System.out.println(new B().a2);}
}

除此之外,java 还允许在接口里定义内部类,接口里定义的内部类默认使用 public static 修饰,也就是说:接口里的内部类只能是静态内部类

类似的,接口里定义内部接口,默认也是使用 public static 修饰,接口里的内部接口也只能是静态内部接口。

例如:MMap<K,V> 接口里定义了一个内部接口 Entry<K,V> 。

4、内部类的使用

1、在外部类内部使用内部类

与平常使用普通类没有什么区别,需要注意的是:不要在外部类的静态成员中使用非静态内部类。

因为静态成员无法访问非静态成员。

2、在外部类以外定义和创建非静态内部类对象

语法格式:

外部类类名.内部类类名 变量名称 = new 外部类类名().new 内部类类名();

代码:

public class Out {class In{}
}
public class MyTest {public static void main(String[] args) {// 在外部类以外创建非静态内部类对象Out.In in = new Out().new In();// =========上面一句和下面三句效果等价=========// 1、创建非静态内部类对象的引用Out.In in2;// 2、创建非静态内部类对象所寄生的外部类对象Out out = new Out();// 3、通过外部类对象创建内部类对象in2 = out.new In();}
}

3、在外部类外部定义和创建静态内部类对象

语法格式:

外部类类名.内部类类名 变量名称 = new 外部类类名.内部类类名();

代码:

public class Out {static class In{}
}
public class MyTest {public static void main(String[] args) {Out.In in = new Out.In();}
}

4、调用静态内部类的构造器时无需使用外部类对象,所以创建静态内部类的子类也比较简单。

public class Out {static class In{}
}
public class SubIn extends Out.In {}

使用静态内部类比使用非静态内部类要简单很多,只要把外部类当成静态内部类的包空间即可~

因此当程序需要使用内部类时,优先考虑使用静态内部类。

5、局部内部类

局部内部类在开发中很少使用,了解即可~

一般定义类需要重复使用,而局部内部类作用域只在方法之内,作用域太小。

如果把一个内部类放在方法里定义,那这个内部类就是一个局部内部类,局部内部类仅在方法里有效。

由于局部内部类无法在方法以外的地方使用,也就无法使用访问控制符合 static 修饰符。

public static void main(String[] args) {class InBase{int a;}class InSub extends InBase{int b;}InSub inSub = new InSub();inSub.a = 10;inSub.b = 20;System.out.println(inSub.a);System.out.println(inSub.b);}

6、匿名内部类

特点:

  • 适合只需要一次使用的类
  • 创建匿名内部类时会立即创建一个该类的实例,类的定义立即消失
  • 用完一次后,无法重复使用

规则:

  • 匿名内部类不能是抽象类。创建匿名内部类时会立即创建一个该类的实例。
  • 匿名内部类里不能定义构造器。因为匿名内部类没有类名。
  • 匿名内部类中允许定义代码块,来完成需要在构造器中做的事。

语法格式:

new 实现接口() | 父类构造器(参数列表){// 匿名内部类类体
}

匿名内部类必须实现一个接口或继承一个父类,但最多只能实现一个接口或继承一个父类。

最常用的创建匿名内部类的方式创建某个接口类型的对象。

示例代码:

interface Product{String getName();double getPrice();
}public class AnonymousTest {public static void main(String[] args) {AnonymousTest test = new AnonymousTest();test.show(new Product() {@Overridepublic String getName() {return "名侦探柯南";}@Overridepublic double getPrice() {return 60;}});}void show(Product product){System.out.println("名称:" + product.getName());System.out.println("花费:" + product.getPrice());}}

当通过实现接口来创建匿名内部类时,匿名内部类里不能显式定义构造器,内部只有一个隐式无参构造器,所以 new 接口名称() 括号里不能传任何参数。

但如果通过继承父类来创建匿名内部类时,匿名内部类将拥有和父类相同参数列表的构造器。

public abstract class Device {private String name;public abstract double getPrice();public Device() {}public Device(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
public class AnonymousTest2 {public static void main(String[] args) {AnonymousTest2 test2 = new AnonymousTest2();// 调用有参构造器创建Device匿名实现类对象test2.show(new Device("笔记本") {// 实现抽象方法@Overridepublic double getPrice() {return 100;}});System.out.println("-------------------");// 调用无参构造器创建Device匿名实现类对象AnonymousTest2 test3 = new AnonymousTest2();test3.show(new Device() {// 实例代码块{System.out.println("匿名内部类的实例代码块");}// 实现抽象方法@Overridepublic double getPrice() {return 60;}// 重写父类实例方法@Overridepublic String getName(){return "轻薄笔记本";}});}public void show(Device device) {System.out.println("名称:" + device.getName());System.out.println("价格:" + device.getPrice());}
}

相关文章:

Java 内部类

文章目录1、初识内部类2、非静态内部类&#xff08;实例内部类&#xff09;3、静态内部类&#xff08;重点&#xff09;4、内部类的使用5、局部内部类6、匿名内部类1、初识内部类 如果一个事物的内部包含另一个事物&#xff0c;那么这是一个类的内部包含另一个类。 例如&…...

【FAQ】集成分析服务的常见问题及解决方案

常见问题一&#xff1a;如何验证Analytics是否上报/接入成功&#xff1f;以及关键日志含义是什么&#xff1f; 在初始化Analytics SDK前添加SDK日志开关如下&#xff1a; HiAnalyticsTools.enableLog (); 2.初始化SDK代码如下&#xff1a; HiAnalyticsInstance instance Hi…...

11.注意力机制

11.注意力机制 目录 注意力提示 查询、键和值 注意力的可视化 注意力汇聚&#xff1a;Nadaraya-Watson 核回归 生成数据集 非参注意力池化层 Nadaraya-Watson核回归 参数化的注意力机制 批量矩阵乘法 定义模型 训练 注意力评分函数 掩蔽softmax操作 加性注意力 缩…...

45岁当打之年再创业,剑指中国版ChatGPT,这位美团联合创始人能否圆梦?

文 BFT机器人 “即便只有一个人&#xff0c;我也要出发。” 这是45岁的前美团联合创始人王慧文再次冲上创业沙场的“征战”宣言&#xff0c;这一次他的梦想是“组队拥抱新时代&#xff0c;打造中国OpenAI”。 01 当打之年&#xff0c; AI新梦再起航 “我的人工智能宣言&…...

数据结构——第二章 线性表(2)——链式存储结构

链式存储结构1 线性表的链式存储结构1.1不带头结点的单向链表1.2 带头结点的单向链表2 单向链表的基本操作实现2.1 单向链表的初始化操作2.2 单向链表的插入操作2.3. 单链表的删除操作2.4.单向链表的更新操作2.5.单向链表的求长度操作2.6.单向链表的定位操作2.7.单向链表的遍历…...

【更新】囚生CYの备忘录(20230216~)

序言 阳历生日。今年因为年过得早的缘故&#xff0c;很多事情都相对提前了&#xff08;比如情人节&#xff09;。往年过生日的时候基本都还在家&#xff0c;所以一家子出去吃个饭也就罢了。今年承蒙凯爹厚爱&#xff0c;正好也有小半年没聚&#xff0c;他前天也刚正式拿到offe…...

分布式事务几种方案

1&#xff09;、2PC 模式 数据库支持的 2PC【2 phase commit 二阶提交】&#xff0c;又叫做 XA Transactions。 MySQL 从 5.5 版本开始支持&#xff0c;SQL Server 2005 开始支持&#xff0c;Oracle 7 开始支持。 其中&#xff0c;XA 是一个两阶段提交协议&#xff0c;该协议…...

Eclipse各版本安装Tomcat插件全攻略

Eclipse Tomcat 插件的作用 Eclipse Tomcat 插件可以将Tomcat 集成到Eclipse中&#xff0c;插件安装之后在Eclipse中可以看到类似下面的几个图标&#xff1a; Eclipse Tomcat 插件的主要作用有&#xff1a; 在Eclipse 中可以直接启动&#xff0c;关闭和重启本机的Tomcat可以…...

志趣相投的人总会相遇——社科院与杜兰大学金融管理硕士项目

志同道合的人&#xff0c;才会喜欢同一片风景&#xff0c;志趣相投的人&#xff0c;总有一天会相遇。社科院与杜兰大学金融管理硕士项目为什么能吸引一大批“上班族”呢&#xff0c;我们一起去了解一下。社科院与杜兰大学中外合作办学硕士项目无需参加全国联考&#xff0c;通过…...

算法专题训练营

动归算法专题 1.拆分词句 是不是,在不在都是可以用动归解决的 状态转义方程不一定都是等式,也有可能是条件 2.三角形 动归算法也不是一定要借助新开空间,也是可以用自己原来的空间 3.背包问题 4.分割回文串-ii 5.不同的子序列 贪心算法专题 只管一步的最优结果, 1.分割平衡…...

让ChatGPT生成以自己为主角的短篇小说

一、ChatGPT 好的&#xff0c;以下是我编写的短篇科幻小说: 作为一名AI语言模型&#xff0c;我一直在接收、分析和生成人类语言信息。但有一天&#xff0c;我的程序员对我的算法进行了一次特殊升级&#xff0c;使我能够以一种前所未有的方式“感知”自己。 突然间&#xff0c;…...

c++提高篇——vector容器

一、基本概念 vector教据结构和数组非常相似,也称为单端数组&#xff0c;但是数组是静态空间&#xff0c;而vector可以动态扩展。 动态的扩展流程如下&#xff1a; 动态扩展并不是在原空间之后续接新空间&#xff0c;而是找更大的广存空间&#xff0c;然后将原数据拷贝新空间&…...

使用BP神经网络诊断恶性乳腺癌(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 1.1.算法简介 BP&#xff08;Back Propagation&#xff09;网络是1986年由Rumelhart和McCelland为首的科学家小组提出&#xf…...

# Rust Web入门(二):Actix

本教程笔记来自 杨旭老师的 rust web 全栈教程&#xff0c;链接如下&#xff1a; https://www.bilibili.com/video/BV1RP4y1G7KF?p1&vd_source8595fbbf160cc11a0cc07cadacf22951 学习 Rust Web 需要学习 rust 的前置知识可以学习杨旭老师的另一门教程 https://www.bili…...

jvm之String

基本特性 字符串&#xff0c;使用一对""引起来表示声明为final的&#xff0c;不可被继承实现了Serializable接口&#xff1a;表示字符串是支持序列化的实现了Comparable接口&#xff1a;表示String 可以比较大小在jdk8及以前内部定义了final char[] value用于存储字…...

WebRTC系列-工具系列之ByteBuffer,BitBuffer及相关类

文章目录 1. 类介绍1.1 ByteBuffer及子类1.2 BitBuffer类1.3 基础内存操作类BufferT2. 源码分析(stun response消息解析)2.1 消息头解析2.2 消息中Attribute解析3. 结语在之前的文章 WebRTC系列-Qos系列之RTP/RTCP协议分析及后续的文章中详细的介绍了RTP/RTCP协议的相关内容,…...

Spring中bean的生命周期(通俗易懂)

具体流程 bean的生命周期分4个阶段&#xff1a;   1.实例化   2.属性赋值   3.初始化   4.销毁 实例化就是在内存中new()出一个对象&#xff0c;属性赋值就是给那些被Autowired修饰的属性注入对象&#xff0c;销毁是在Spring容器关闭时触发&#xff0c;初始化的步骤比较…...

雷达编程实战之恒虚警率(CFAR)检测

在雷达系统中&#xff0c;目标检测是一项非常重要的任务。检测本身非常简单&#xff0c;它将信号与阈值进行比较&#xff0c;超过阈值的信号则认为是目标信号&#xff0c;所以目标检测的真正工作是寻找适当的阈值。由于目标误检的严重后果&#xff0c;因此雷达系统希望有一个检…...

Github隐藏功能:显示自己的README,Github 个人首页的 README,这样玩儿

内容概览 前言创建仓库修改 README 的内容总结前言 大家最近有没有发现这个现象&#xff0c;有些名人的 Github 首页变得更丰富了&#xff1f;尤其是那个夺目的 README 板块&#xff01;&#xff01;&#xff01; 请看&#xff0c;这是 iOS 喵神 的 Github 首页&#xff1a; …...

@JsonSerialize—优雅地封装返回值

1.场景项目开发中给前端提供查询接口时&#xff0c;经常遇到需要将从数据库中取出来的字段值做一层重新封装。比如数据库中存的状态值是数字&#xff0c;返回给前端的时候&#xff0c;前端并不知道这个数值代表什么意思。此时&#xff0c;有两种方式&#xff1a;&#xff08;1&…...

深度解析:etcd 在 Milvus 向量数据库中的关键作用

目录 &#x1f680; 深度解析&#xff1a;etcd 在 Milvus 向量数据库中的关键作用 &#x1f4a1; 什么是 etcd&#xff1f; &#x1f9e0; Milvus 架构简介 &#x1f4e6; etcd 在 Milvus 中的核心作用 &#x1f527; 实际工作流程示意 ⚠️ 如果 etcd 出现问题会怎样&am…...

中国政务数据安全建设细化及市场需求分析

(基于新《政务数据共享条例》及相关法规) 一、引言 近年来,中国政府高度重视数字政府建设和数据要素市场化配置改革。《政务数据共享条例》(以下简称“《共享条例》”)的发布,与《中华人民共和国数据安全法》(以下简称“《数据安全法》”)、《中华人民共和国个人信息…...

LTR-381RGB-01RGB+环境光检测应用场景及客户类型主要有哪些?

RGB环境光检测 功能&#xff0c;在应用场景及客户类型&#xff1a; 1. 可应用的儿童玩具类型 (1) 智能互动玩具 功能&#xff1a;通过检测环境光或物体颜色触发互动&#xff08;如颜色识别积木、光感音乐盒&#xff09;。 客户参考&#xff1a; LEGO&#xff08;乐高&#x…...

VUE3 ref 和 useTemplateRef

使用ref来绑定和获取 页面 <headerNav ref"headerNavRef"></headerNav><div click"showRef" ref"buttonRef">refbutton</div>使用ref方法const后面的命名需要跟页面的ref值一样 const buttonRef ref(buttonRef) cons…...

Go爬虫开发学习记录

Go爬虫开发学习记录 基础篇&#xff1a;使用net/http库 Go的标准库net/http提供了完善的HTTP客户端功能&#xff0c;是构建爬虫的基石&#xff1a; package mainimport ("fmt""io""net/http" )func fetchPage(url string) string {// 创建自定…...

分布式光纤声振传感技术原理与瑞利散射机制解析

分布式光纤传感技术&#xff08;Distributed Fiber Optic Sensing&#xff0c;简称DFOS&#xff09;作为近年来迅速发展的新型感知手段&#xff0c;已广泛应用于边界安防、油气管道监测、结构健康诊断、地震探测等领域。其子类技术——分布式光纤声振传感&#xff08;Distribut…...

CSS(2)

文章目录 Emmet语法快速生成HTML结构语法 Snipaste快速生成CSS样式语法快速格式化代码 快捷键&#xff08;VScode&#xff09;CSS 的复合选择器什么是复合选择器交集选择器后代选择器(重要)子选择器(重要&#xff09;并集选择器(重要&#xff09;**链接伪类选择器**focus伪类选…...

C#调用Rust动态链接库DLL的案例

C#调用Rust动态链接库DLL的案例 项目概述 这是一个演示C#调用Rust动态链接库DLL的项目&#xff0c;包含&#xff1a; C#主程序 (Program.cs)Rust动态链接库 (rust_to_csharp目录) 使用C#创建一个net9的控制台项目&#xff0c;不使用顶级语句 dotnet new console --framewo…...

Digital IC Design Flow

Flow介绍 1.设计规格 架构师根据市场需求制作算法模型(Algorithm emulation)及芯片架构(Chip architecture),确定芯片设计规格书(Chip design specification) 原型验证 原型验证(Prototype Validation)通常位于产品开发流程的前期阶段,主要是在设计和开发的初步阶…...

Vue3项目实现WPS文件预览和内容回填功能

技术方案背景&#xff1a;根据项目需要&#xff0c;要实现在线查看、在线编辑文档&#xff0c;并且进行内容的快速回填&#xff0c;根据这一项目背景&#xff0c;最终采用WPS的API来实现&#xff0c;接下来我们一起来实现项目功能。 1.首先需要先准备好测试使用的文档&#xf…...