一.equal方法
1.1 引出equal方法
思考一下输出语句输出的内容。
在这段代码中:
-
System.out.println(s1 == s2);
输出false
。因为使用new
关键字创建的String
对象会在堆内存中开辟新的空间,所以s1
和s2
是两个不同的对象,它们的引用不同。 -
System.out.println(s1 == s3);
输出false
。s1
是通过new
创建的对象,存放在堆内存中;而s3
是直接使用字符串常量创建的,会先在字符串常量池中查找是否已经存在 "abc" ,如果存在则直接引用,否则创建并放入常量池。所以s1
和s3
的引用不同。 -
System.out.println(s3 == s4);
输出true
。因为s3
和s4
都是直接使用字符串常量创建的,当在常量池中已经存在 "abc" 时,它们会引用同一个常量池中的对象,所以引用相同。
那么我们如果想比较两个new对象的内容应该怎么比较呢?
我们就要用到equal方法了。
equal是比较内容的。
这是方法内部的原理。
谁调用了equal谁就是this。
1.2:equal的延深
1.2.1 问题
上面的问题我们解决了,如果我们想比较两个类对象的内容应该怎么比较呢?
打印出了false。
为什么呢?
这是因为在默认情况下,如果您没有在自定义的 testdemo3
类中重写 equals
方法,那么使用的是从 Object
类继承来的 equals
方法,而该方法默认是通过比较对象的引用是否相等来判断是否相等的。
在您的代码中,testdemo3
和 testdemo31
是两个通过 new
操作符创建的不同对象,它们的引用不同,所以 equals
方法返回 false
。
那String也是创建新对象,引用也不同,为什么用equal就会打印出来true呢?
当使用 equals
方法比较两个 String
对象时,如果它们的内容相同,就会打印 true
,这是因为 String
类已经重写了 Object
类的 equals
方法。
1.2.2 重写equal方法
那我们应该怎么重写equal方法呢?
用这个方法就可以了,getClass()!= o.getClass()
:获取当前对象的类对象(通过 getClass()
方法),并与传入对象 o
的类对象进行比较。如果两个类对象不相同,说明它们不是同一类型的对象,也就不可能相等,直接返回 false
。
为什么还要重写hashCode方法呢?
1.一致性原则:根据 Java 的约定,如果两个对象通过 equals
方法比较相等,那么它们的 hashCode
值也必须相等。反之,如果两个对象的 hashCode
值不同,那么它们一定不相等;但如果 hashCode
值相同,它们不一定相等(因为可能存在哈希冲突)。
二.Comparable接口
2.1 引出Comparable接口
现在我想比较一下xiaoming和xiaohong谁的年龄大,此时就可以用到Comparable接口中的compareTo方法了。
接接口后面的<>里面填上需要用到的类,还需要重写compareTo方法。
此时就可以比较了
通过返回的值可知,student11的年龄大于student1的年龄。
2.2 详细用法
接下来我们再来完成一下学生年龄的排序。
myarray中的参数是表示实现这个接口的类数组。
结果
比较name无意义我就不再写了。
2.3 优点:
1. 内聚性:将比较逻辑直接嵌入到要比较的类中,使相关的功能在同一个地方,增强了代码的内聚性和封装性。
2. 自然排序:定义了对象的自然排序方式,使得在需要对该类型的对象进行排序时,无需额外提供比较器,使用起来更加直观和方便。
3. 更加的通俗易懂。
2.4 缺点:
1.灵活性受限:一旦确定了类实现 Comparable
接口的比较逻辑,就难以在不同的上下文中更改比较方式。如果后续有新的比较需求,可能需要修改类的代码,这可能会影响到使用该类的其他部分代码。
2. 单一比较规则:一个类只能定义一种自然的比较规则。如果在不同场景下需要根据不同的属性或规则进行比较,就无法直接使用 Comparable
提供的默认比较方式。
3. 类的修改影响范围:如果一个被广泛使用的类修改了其 Comparable
的比较逻辑,可能会导致所有依赖于该比较逻辑的代码都受到影响,需要进行相应的调整和测试。
三.Compartor接口
3.1 引出Compartor接口
为了解决Comparable的受限缺点的话,引入了Compartoe接口,compareTo方法只能写在该类中只能比较一个类属性,没有解决办法,所以我们引入了Compartor接口。
这时就比较灵活,能够通过age或者grade随便排序和比较。
这样就比较灵活了。
3.2 Array.sort方法
Arrays.sort(s, ageComparator)
的原理是基于快速排序或归并排序等高效的排序算法,并结合传入的 Comparator
对象 ageComparator
来确定元素的顺序。
在排序过程中,每次需要比较两个元素时,都会调用 ageComparator
的 compare
方法来确定它们的相对顺序。compare
方法返回一个整数值,根据这个值来决定两个元素在排序后的数组中的位置。
具体的排序算法会根据数组的大小和初始状态选择最优的策略,以尽可能高效地对数组进行排序。
如果没有传入 Comparator
对象(即 Arrays.sort(s)
),并且数组元素的类型实现了 Comparable
接口,那么会使用元素自身的 compareTo
方法来进行比较和排序。
上面的已经有演示了,我再演示一下Arrays.sort(s)这个。
3.3 优点:
1. 灵活性:可以为同一个类提供多种不同的比较策略,根据不同的需求在不同的场景中使用不同的 Comparator
实现。
2. 解耦:比较逻辑与被比较的类分离,使得类的设计更加专注于自身的核心功能,而比较逻辑可以在外部独立定义。
3. 动态性:可以在运行时根据具体的条件创建和使用不同的 Comparator
,具有更强的动态性。
3.4 缺点
1. 代码复杂:需要额外创建 Comparator
类,增加了代码量和复杂性。
3.5 二者的一些主要区别
1. 实现的位置:
Comparable
是在要进行比较的类内部实现比较逻辑。Comparator
则是在类的外部单独定义比较规则。
2.灵活性
Comparable
为类定义了一种固定的、自然的排序方式。Comparator
更加灵活,可以根据不同的需求为同一个类定义多种不同的比较方式。
3.代码结构
- 使用
Comparable
时,比较逻辑与类的其他功能紧密结合。 - 使用
Comparator
时,比较逻辑相对独立,代码结构更清晰。
4.类的修改
- 更改
Comparable
的比较逻辑需要修改类的代码。 Comparator
的修改不会影响到被比较的类本身。
5.适用场景
- 如果类本身具有明确且唯一的自然排序方式,适合使用
Comparable
。 - 当需要在不同场景下对类进行不同方式的排序,或者类本身不适合修改来实现比较逻辑时,适合使用
Comparator
。
6.集合排序
- 对于实现了
Comparable
的类的对象数组,可直接使用Arrays.sort
进行排序。 - 对于未实现
Comparable
的类的对象数组,若要排序则必须提供Comparator
对象给Arrays.sort
。
四.结束语
感谢大家的查看,希望可以帮助到大家,做的不是太好还请见谅,其中有什么不懂的可以留言询问,我都会一一回答。 感谢大家的一键三连。