Java常用Comparable接口、Comparator比较器和Cloneable接口

1、Comparable接口

1.1 举例

给对象数组排序
给定一个学生类

class Student { 
 private String name; 
 private int score; 
 public Student(String name, int score) { 
 this.name = name; 
 this.score = score; 
 } 
 
 @Override 
 public String toString() { 
 return "[" + this.name + ":" + this.score + "]"; 
 } 
} 

再给定一个学生对象数组, 对这个对象数组中的元素进行排序(按分数降序).

Student[] students = new Student[] { 
 new Student("张三", 95), 
 new Student("李四", 96), 
 new Student("王五", 97), 
 new Student("赵六", 92), 
}; 

按照我们之前的理解, 数组我们有一个现成的 sort 方法, 能否直接使用这个方法呢?

Arrays.sort(students); 
System.out.println(Arrays.toString(students)); 
// 运行出错, 抛出异常. 
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to 
java.lang.Comparable 

和普通的整数不一样, 两个整数是可以直接比较的, 大小关系明确. 而两个学生对象的大小关系怎么确定? 需要我们额外指定.
让我们的 Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法

class Student implements Comparable { 
 private String name; 
 private int score; 
 public Student(String name, int score) { 
 this.name = name; 
 this.score = score; 
 } 
 @Override 
 public String toString() { 
 return "[" + this.name + ":" + this.score + "]"; 
 } 
 @Override 
 public int compareTo(Object o) { 
 Student s = (Student)o; 
 if (this.score > s.score) { 
 return -1; 
 } else if (this.score < s.score) { 
 return 1; 
 } else { 
 return 0; 
 } 
 } 
} 

在 sort 方法中会自动调用 compareTo 方法. compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.
然后比较当前对象和参数对象的大小关系(按分数来算).
如果当前对象应排在参数对象之前, 返回小于 0 的数字;
如果当前对象应排在参数对象之后, 返回大于 0 的数字;
如果当前对象和参数对象不分先后, 返回 0;
再次执行程序, 结果就符合预期了.

// 执行结果
[[王五:97], [李四:96], [张三:95], [赵六:92]] 

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

2、Comparator比较器

Comparable和Comparator他们的功能是差不多的,只是前者对类的侵入性比较强,写好了就不容易更改,后者对类的侵入性弱,灵活。
在这里插入图片描述

3 Cloneable接口

3.1Cloneable接口使用

Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出CloneNotSupportedException 异常.

class Animal implements Cloneable { 
 private String name; 
 @Override 
 public Animal clone() { 
 Animal o = null; 
 try { 
 o = (Animal)super.clone(); 
 } catch (CloneNotSupportedException e) { 
 e.printStackTrace(); 
 } 
 return o; 
 } 
} 
public class Test { 
 public static void main(String[] args) { 
 Animal animal = new Animal(); 
 Animal animal2 = animal.clone(); 
 System.out.println(animal == animal2); 
 } 
} 
// 输出结果
// false 

3.2浅拷贝 VS 深拷贝

深拷贝:比如你想去学习做包子,当你能把包子皮和包子馅都能做出来了,你就学会了,就是拷贝一个对象,还能把对象里面的对象都拷贝出来,就是深拷贝。
浅拷贝:比如你想去学习做包子,但是你只是学会了做包子皮,包子馅只是得到了配方,还需要进一步操作,才能做出完整的包子。就是拷贝一个对象,你只是拷贝到了对象里面对象的地址,这就是浅拷贝。
Cloneable 拷贝出的对象是一份 "浅拷贝

public class Test { 
 static class A implements Cloneable { 
 public int num = 0; 
 @Override 
 public A clone() throws CloneNotSupportedException { 
 return (A)super.clone(); 
 } 
 } 
 static class B implements Cloneable { 
 public A a = new A(); 
 @Override 
 public B clone() throws CloneNotSupportedException { 
 return (B)super.clone(); 
 } 
 } 
 public static void main(String[] args) throws CloneNotSupportedException { 
 B b = new B(); 
 B b2 = b.clone(); 
 b.a.num = 10; 
 System.out.println(b2.a.num); 
 } 
} 
// 执行结果
10 

通过 clone 拷贝出的 b 对象只是拷贝了 b 自身, 而没有拷贝内部包含的 a 对象. 此时 b 和 b2 中包含的 a 引用仍然是指向同一个对象. 此时修改一边, 另一边也会发生改变

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值