内部类, 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.mzph.cn/news/178175.shtml

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

相关文章

Unity中Shader的BRDF解析(一)

文章目录 前言现在我们主要来看Standard的 漫反射 和 镜面反射一、PBS的核心计算BRDF二、Standard的镜面高光颜色三、具体的BRDF计算对于BRDF的具体计算&#xff0c;在下篇文章中&#xff0c;继续解析 四、最终代码.cginc文件Shader文件 前言 在上篇文章中&#xff0c;我们解析…

DDR-MIG 学习记录

MIG调试总结&#xff1a; 对vivado软件中用于控制DDR2 / DDR3 的 控制器MIG(Memory Interface Generator)IP核进行了仿真测试&#xff0c;以学习如何用IP核来控制FPGA板载SDRAM的读写。我们只需要学会MIG的接口控制就可以。 ①配置IP核 Xilinx 的 DDR 控制器的名称简写为 MIG&…

brk和sbrk

在计算机程序中&#xff0c;“program break”通常指的是堆的当前内存边界。当我们改变堆的大小&#xff08;即分配或释放内存&#xff09;&#xff0c;其实就是在命令内核改变进程的“program break”位置。 最初&#xff0c;“program break”正好位于未初始化数据段(bss)末…

vue3中的动态component组件

is属性来指定要渲染的组件(填写组件名&#xff09; 多个子组件通过component标签挂载在同一个父组件中&#xff0c; 可以修改is属性进行动态切换组件。 可以搭配<keep-alive></keep-alive>使用。 父组件代码&#xff1a; <template><div style"fon…

2017年五一杯数学建模A题公交车排班问题解题全过程文档及程序

2017年五一杯数学建模 A题 公交车排班问题 原题再现 随着徐州市经济的快速发展&#xff0c;公交车系统对于人们的出行扮演着越来越重要的角色。在公交车资源有限的情况下&#xff0c;合理的编排公交车的行车计划成为公交公司亟待解决的问题。以下给出公交车排班问题中的部分名…

【NI-RIO入门】为CompactRIO供电

在大多数情况下&#xff0c;您可以使用可直接连接系统的电源&#xff0c;例如墙上的电源插座。但是&#xff0c;某些应用程序或环境缺乏可用电源&#xff0c;您必须使用其他电源&#xff0c;例如电池。无论您是否有可用电源&#xff0c;您可能都希望通过为系统提供一些冗余来确…

洛谷 P1605 USACO迷宫 (详细解析和AC代码)【深搜+打表】

P1605 迷宫 前言题目题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题目分析注意事项 代码后话王婆卖瓜 题目来源 前言 没什么好说的深搜yyds&#xff01;直接深搜一遍过&#xff01; 题目 题目描述 给定一个 N M N \times M NM 方格的迷宫&#xff0c;迷…

python加速方法:GPU加速(numba库)Demo及编写注意事项

上周使用GPU加速了一个算法&#xff0c;效果特别惊艳&#xff0c;由于算法代码本身没有太大参考价值&#xff0c;所以这里只记录了一些心得体会&#xff0c;以便后续遇到问题进行参考排查 numba加速代码编写注意事项 numba加速代码编写一定要注意&#xff1a; 1、开辟空间&am…

【Java并发】聊聊不安全的HashMap以及ConcurrentHashMap

在实际的开发中&#xff0c;hashmap是比较常用的数据结构&#xff0c;如果所开发的系统并发量不高&#xff0c;那么没有问题&#xff0c;但是一旦系统的并发量增加一倍&#xff0c;那么就可能出现不可控的系统问题&#xff0c;所以在平时的开发中&#xff0c;我们除了需要考虑正…

Python从入门到精通(黑马课程)

目录 运算符 数字运算符 比较运算符 逻辑运算符 转义字符 变量使用 变量定义 变量类型 变量命名 变量函数 input函数 type函数 条件语句 If 格式 案例1&#xff0c;判断年龄 案例2&#xff0c;借钱 案例3&#xff0c;and、or应用 循环语句 for 格式 案例…

如何使用Cloudreve将个人电脑打造为私有云盘并实现远程访问

文章目录 1、前言2、本地网站搭建2.1 环境使用2.2 支持组件选择2.3 网页安装2.4 测试和使用2.5 问题解决 3、本地网页发布3.1 cpolar云端设置3.2 cpolar本地设置 4、公网访问测试5、结语 1、前言 云存储概念兴起后&#xff0c;现在市面上也已经有了很多公有云盘。但一段时间后…

redis基本数据结构

Redis入门&#xff1a;五大数据类型 文章目录 Redis入门&#xff1a;五大数据类型一.概述二.Redis的基本了解三.Redis五大数据类型1.String (字符串)2.List(列表)3.Set集合(元素唯一不重复)4.Hash集合5.zSet(有序集合) 一.概述 什么是Redis Redis&#xff08;Remote Dictiona…

Java 之 lambda 表达式(一)

目录 一. 前言 二. lambda 表达式语法 2.1. 语法1&#xff1a;无参&#xff0c;无返回值 2.2. 语法2&#xff1a;一个参数&#xff0c;无返回值 2.3. 语法3&#xff1a;两个参数&#xff0c;lambda 体中有多条语句 2.4. 语法4&#xff1a;两个以上参数&#xff0c;有返回…

C++ STL-----容器

STL容器就是将运用最广泛的一些数据结构实现出来 常用的数据结构&#xff1a;数组, 链表,树, 栈, 队列, 集合, 映射表 等 这些容器分为序列式容器和关联式容器两种: 序列式容器:强调值的排序&#xff0c;序列式容器中的每个元素均有固定的位置。 关联式容器:二叉树结构&…

深入了解Java8新特性-日期时间API:LocalDateTime类

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概22000多字&#xff0c;预计阅读时间长需要20分钟以上。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&…

c++没有返回值的返回值

上面的函数search没有返回值,因为a不等于1,但是输出的时候会输出6.这恰巧是x的值,如果我们希望a不等于1时返回x,那么这种结果反而是正确的.有时候这种错误的代码可能产生正确的结果反而会加大debug难度 int search(int n) { 00007FF66DB723E0 mov dword ptr [rsp8],e…

简易版扫雷+代码分析

前言&#xff1a; 实验一个简易版的扫雷&#xff0c;也要两百来行的代码&#xff0c;因此为了代码整洁&#xff0c;维护起来方便&#xff0c;这里我们和前期实现的三子棋一样&#xff0c;也弄一个游戏的头文件game.h用来装各种头文件以及函数的声明以及宏定义、预处理信息&…

视频文件+EasyDarwin做摄像机模拟器模拟RTSP流很方便,还能做成系统服务,方法与流程

之前我看到过一家人工智能做算法的企业&#xff0c;用EasyDarwinFFMPEG做了一个摄像机的模拟器&#xff0c;方法大概是&#xff1a; 用ffmpeg读取mp4等类型的视频文件&#xff08;当然ffmpeg啥都能读取&#xff09;&#xff0c;再以RTSP协议的形式推送给EasyDarwin&#xff1b…

为IP地址申请SSL证书

SSL&#xff08;Secure Sockets Layer&#xff09;是一种网络协议&#xff0c;用于在浏览器与服务器之间建立安全、加密的连接。SSL证书是用于证明您的网站身份并启用HTTPS&#xff08;超文本传输安全协议&#xff09;的安全文件。这种协议可以确保用户与您的网站之间的所有通信…

统计学中两组数据如何进行差异性(相关性)分析?

变量说明&#xff1a; 在确定分析方法前&#xff0c;我们需要了解手中的数据类型&#xff0c;这是最基础也是有必要的&#xff0c;在所有的数据类型中&#xff0c;我们将数据类型分为分类变量也为定类变量和连续变量也称为定量变量&#xff0c;那么什么是定类变量&#xff1f;…