内部类, Comparable接口, Comparator接口, Cloneable接口 ---java

目录

一. 内部类

1.1 静态内部类

1.2 实例内部类

1.3匿名内部类

二. 接口的使用实例 

2.1 Comparable接口

2.2 Comparator接口 ---比较器

2.3 Cloneable接口 

深拷贝浅拷贝 


一. 内部类

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

注:内部类和外部类共用同一个java源文件,但是经过编译之后,内部类会形成单独的字节码文件 ,命名格式:外部类名字$内部类名字.class

内部类可以分为四类:

1. 静态内部类

2. 实例内部类

3. 匿名内部类(最常用)

4. 局部内部类 (不常用,不做讲解)

1.1 静态内部类

static修饰的内部成员类称为静态内部类。  

上述代码, 我们可以看到,

1. 在静态内部类中定义的成员变量(方法), 可以是static修饰的,

2. 在静态内部类中的成员方法, 可以直接访问在静态内部类中定义的成员变量(方法)在外部类中定义的static修饰的变量(方法), 但不能直接访问外部类中没有被static修饰的变量

 3. 想要在静态内部类的方法中访问外部类的成员变量, 需要创建一个外部类型的对象, 通过对象去访问.

4. 在外部类中创建一个方法, 在这个方法里面, 可以直接创建静态内部类的对象

5. 在外部类之外, 想要创建静态内部类对象,  不需要先创建外部类对象, 必须通过外部类.  去使用

1.2 实例内部类

即未被 static 修饰的成员内部类。

 

由上述代码, 我们可以得到:

1. 实例内部类中不能定义static修饰的变量(方法) , 如果想定义, 需要加final

 2 . 在外部类中创建一个方法, 在这个方法里面, 可以直接创建实例内部类的对象

 3. 在外部类之外, 想要创建实例内部类对象,  需要先创建外部类对象, 通过外部类对象的引用外部对象. 去创建实例内部类对象

4. 在实例内部类的方法中, 都可直接访问外部类和内部类中的任意访问限定符修饰的成员变量(方法) 

 5. 如果外部类和实例内部类中具有相同名称成员时,优先访问的是内部类自己的,  加this. 还访问自己的.

如果要访问外部类同名成员:外部类名称.this.同名成员名字

或像静态内部类一样, 创建一个外部类对象, 对对象的引用

1.3匿名内部类

我们先看一下什么是匿名对象

 如果以后的场景是, 只是用一次对象, 那么可以使用匿名对象.

使用匿名内部类, 首先我们先创建一个接口

正常情况下我们是这样使用的

而匿名内部类, 可以不用创建类TestA, 直接匿名实现接口, 并对其重写

 或更高阶的写法:

 当然, 也可以匿名new类. 

二. 接口的使用实例 

Java 中内置了一些很有用的接口:

2.1 Comparable接口

定义两个字符串

如何比较两个字符串的大小呢?

显然, 是错误的,java当中, 不可以直接比较引用类型的大小 

那么, 我们就可以借助String类型里面的compareTo()方法进行比较

 按住Ctrl我们点进compareTo发现 :

这个方法是通过重写接口中的方法得来的, 那么我们点进去黄框, 就会发现:

原来String类型, 可以进行字符串的比较, 是因为引用了Comparable这个接口, 然后在类中重写compareTo这个方法实现的

 那么同理, 当我们自定义一个类, 创建两个对象时, 想要比较两个对象的大小, 我们就可以通过implements Comparable<>, 并在类中重写compareTo方法, 根据自己的需求, 自定义要比较的标准.

举例:

我们也可以以姓名为标准进行比较:

 再举例:

定义一个数组, 通过Arrays.sort()对数组进行排序:

运行时我们发现报错:

 原因是, Arrays.sort() 不知道以什么标准进行比较

注意事项: 对于 sort 方法来说, 需要传入的数组的每个对象都是 "可比较" 的, 需要具备 compareTo 这样的能力. 通过重写 compareTo 方法的方式, 就可以定义比较规则.

所以Student类, 需要实现Comparable接口, 并重写compareTo方法 

结果: 

2.2 Comparator接口 ---比较器

比较什么, 就定义一个类, 实现Comparator接口, 重写compare方法, 将比较的对象当做参数传递过去,  非常灵活

 

再如上述对数组排序时, 可以使用Arrays.sort(数组名, 比较器), 这样在比较时, 就会使用比较器的方法进行排序. 

2.3 Cloneable接口 

现在, 我们定义一个对象, 我们想把第一个对象克隆到第二个对象

我们看到, Object类中有clone()方法, 我们想拿过来直接用, 发现:

不允许我们直接用, 我们点进去clone()方法可以看到:

它是被protected修饰的, 我们学过, 在不同包中, 想要访问protected修饰的方法, 必须是在子类中访问, 需要通过super进行访问, 所以我们要对clone方法进行重写. 

利用快捷方法:Alt + Insert

这个方法就被创建好了. 

我们看到:

返回类型是Object,  所以我们要调用这个方法时, 要进行向下转型

后面跟着一串throws CloneNotSupportedException, 这个我们先不管后面讲, 先照抄在main方法后面. 

此时运行我们发现报错:

解决方法:

要实现一个Cloneable接口, 表示此类可以被克隆. 

到此为止, 才算克隆成功. 

我们点进去Cloneable接口可以看到:

 

里面什么也没有, 我们管这种接口叫做空接口/标记接口

一个类实现了空接口/标记接口, 那么表示当前这个类, 是可以被怎么样的, 如实现Cloneable, 表示此类可以被克隆. 

 

深拷贝浅拷贝 

什么是深拷贝浅拷贝呢?

我们看一个例子:

在对象里创建一个对象:

上述代码我们修改了person2中的m的money的值, 理论上来说输出的结果应该为:

person1还是6.6 ,person2被改成9.9 ,但是当我们运行起来后发现:

person1的值也被改了. 

这是为什么呢? 我们画图理解一下:

所以person1, person2修改之前都是6.6. 此时, 两个m都指向同一块空间

所以, 修改money的值, person1和person2都变. 

这就是浅拷贝, 只拷贝了原来的对象, 但对象里的对象没有被拷贝. 

那么同理:深拷贝是指完全克隆出一个独立于原来的对象的对象 

那么, 上述代码, 如果想要达到深拷贝效果, Money这个类必须也是一个可以拷贝的类, 所以Money类要实现Cloneable接口, 并重写父类中的clone方法.

这样我们就做好了准备工作, 但是在哪里怎么调用这个方法呢?

在Person的clone()里:

 

 

 

此时person1的m 和person2的m 是两个独立的对象, 相互不耽误. 所以, 修改person2的m的money的值, person1不变, person2变.

完整代码如下:

class Money implements Cloneable{public double money = 6.6;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
class Person implements Cloneable{public String name;public Money m;public Person(String name) {this.name = name;m=new Money();}@Overrideprotected Object clone() throws CloneNotSupportedException {Person tmp = (Person) super.clone();tmp.m = (Money) this.m.clone();return tmp;}
}
public class Test2 {public static void main(String[] args)throws CloneNotSupportedException{Person person1 = new Person("zhangsan");Person person2 =(Person) person1.clone();System.out.println("person1修改之前:"+person1.m.money);System.out.println("person2修改之前:"+person2.m.money);person2.m.money = 9.9;System.out.println("person1修改之后:"+person1.m.money);System.out.println("person2修改之后:"+person2.m.money);}
}

可见, 是不是深拷贝, 是要看程序猿实现的怎么样.

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

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

相关文章

ECRS生产工时分析软件:工业效率提升的隐形引擎

降本增效往往是企业开工规划的第一步。那到底降什么本&#xff0c;增什么效呢&#xff0c;对于很多企业来说&#xff0c;都是从采购成本入手&#xff0c;结果采购成本是降下来了&#xff0c;但是整体品质却下降了。实际上&#xff0c;要降本增效&#xff0c;优化现场管理才是企…

CentOS7.9虚拟机EDA环境,支持模拟集成电路、数字集成电路、数模混合设计全流程,包含工艺库

目录 前言一、配置准备工作1.1 网盘文件说明1.2 EDA工具介绍 二、虚拟机运行2.1 虚拟机工具启动2.2 软件配置使用2.3 Module工具切换环境变量和软件版本 获取方法附录&#xff1a;部分EDA工具运行效果图 前言 搭建了CentOS7.9虚拟机环境&#xff0c;工具包括但不限于&#xff…

Redis缓存设计典型问题

目录 缓存穿透 缓存失效&#xff08;击穿&#xff09; 缓存雪崩 热点缓存key重建优化 缓存与数据库双写不一致 缓存穿透 缓存穿透是指查询一个根本不存在的数据&#xff0c; 缓存层和存储层都不会命中&#xff0c; 通常出于容错的考虑&#xff0c; 如果从存储层查不到数据…

C++ day38 动态规划 斐波那契数列 爬楼梯 使用最小花费爬楼梯

题目1&#xff1a;509 斐波那契数列 题目链接&#xff1a;斐波那契数列 对题目的理解 斐波那契数列由0和1开始&#xff0c;后面每一项数字(F(n))都是前两个数字的和&#xff0c;给一个n&#xff0c;计算F(n)&#xff0c;&#xff08;0<n<30&#xff09; 动规五部曲 …

基于springBoot+mysql实现的竞赛管理系统

基于springBootmysql实现的竞赛管理系统&#xff0c;演示地址:系统登录 - 软件学院比赛管理系统 管理员账号&#xff1a;1&#xff0c;密码:1 包括比赛管理&#xff0c;队伍管理&#xff0c;教师管理&#xff0c;经费管理&#xff0c;学生管理&#xff0c;比赛结果&#xff0c;…

3D打印报价系统

一款3d打印报价系统不仅可以展示三维模型&#xff0c;还能自动计算模型的相关信息&#xff0c;如面积、体积和尺寸信息。 用户上传三维模型后&#xff0c;系统会自动为其生成一个报价页面。在这个页面上&#xff0c;用户可以看到他们模型的所有相关信息&#xff0c;包括面积、体…

Ubuntu 环境安装 Kafka、配置运行测试 Kafka 流程笔记

Kafka 介绍 Kafka 是一个由 Apache 软件基金会开发的开源流式处理平台。它被设计用于处理大规模数据流&#xff0c;提供高可靠性、高吞吐量和低延迟的消息传递系统。Kafka 可以用于构建实时数据管道和流式应用程序&#xff0c;让不同应用、系统或者数据源之间能够高效地进行数…

HCIA-H12-811题目解析(1)

1、【多选题】关于动态 MAC 地址表说法正确的是&#xff1f; A、通过报文中的源MAC地址学习获得的动态MAC表项会老化 B、通过查看指定动态MAC地址表项的个数&#xff0c;可以获取接口下通信的用户数 C、在设备重启后&#xff0c;之前的动态表项会丢失 D、在设备重启后&…

Alibaba微服务组件Nacos配置中心实战

Nacos 配置中心 配置中心作用 配置中心就是一种统一管理各种应用配置的基础服务组件。使得配置信息集中管理&#xff0c;易于维护&#xff0c;并且可以动态更新配置&#xff0c;使得分布式系统更加稳定可靠。 什么是Nacos配置中心 Nacos 提供用于存储配置和其他元数据的 ke…

奇异值分解SVD(Singular Value Decomposition)

一种理解方式&#xff0c;值得学习&#xff08;分解时空矩阵&#xff09; 先在这里阐述一下SVD的用途吧&#xff0c;具体细节稍后再做补充 1.通过SVD对数据的处理&#xff0c;我们可以使用小得多的数据集来表示原始数据集&#xff0c;这样做实际上是去除了噪声和冗余信息&…

re:Invent 2023 开发者指南来了!@开发者们,Let‘s 构!

开发者们看过来! 云计算领域的风向标、科技界的年度重磅盛会 2023 亚马逊云科技 re:Invent 将于 11 月 27 日在美国拉斯维加斯盛大启幕! 学习、互动、交流、比拼…… 作为世界开发者的年度技术狂欢盛宴 美国现场或国内互动将有哪些精彩环节? 开发者们&#xff0c;Lets …