1.Comparable 接口
在Java中,我们对一个元素是数字的数组可以使用sort方法进行排序,如果要对一个元素是对象的数组按某种规则排序,就会用到Comparable接口
当实现Comparable接口后,sort会自动调用Comparable接口里的compareTo 方法. compareTo 的参数是 Object
注意:
如果当前对象应排在参数对象之前, 返回小于 0 的数字;
如果当前对象应排在参数对象之后, 返回大于 0 的数字;
如果当前对象和参数对象不分先后, 返回 0;
对于 sort 方法来说, 需要传入的数组的每个对象都是 "可比较" 的, 需要具备 compareTo 这样的能力. 通 过重写 compareTo 方法的方式, 就可以定义比较规则.
缺点:对于Comparable接口来说,一个类里面只能实现一个compareTo方法,也就是说实现Comparable接口在排序时只能按一种规则排序,如果想要使用其他方法排序就必须重写compareTo方法
参考代码:
class Student implements Comparable<Student>{
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// @Override
// public int compareTo(Student o) {
// return this.age-o.age;
// }
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
return this.name.compareTo(o.name);
}
}
public class T1 {
public static void main(String[] args) {
Student[] students = new Student[3];
students[0] = new Student("张三", 12);
students[2] = new Student("李四", 14);
students[1] = new Student("王五", 10);
System.out.println("排序前:" + Arrays.toString(students));
Arrays.sort(students);
System.out.println("排序后:" + Arrays.toString(students));
}
}
2.Comparator接口
Comparator接口完美解决了Comparable接口的缺点
参考代码:
class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class AgeComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.age-o2.age;
}
}
class NameComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
public class T1 {
public static void main(String[] args) {
Student[] students=new Student[3];
students[0]=new Student("张三",12);
students[2]=new Student("李四",14);
students[1]=new Student("王五",10);
System.out.println("排序前:"+Arrays.toString(students));
AgeComparator ageComparator=new AgeComparator();
NameComparator nameComparator=new NameComparator();
Arrays.sort(students,ageComparator);
System.out.println("排序后:"+Arrays.toString(students));
Arrays.sort(students,nameComparator);
System.out.println("排序后:"+Arrays.toString(students));
}
}
3.对象比较equals方法
在Java中,==进行比较时:
a.如果==左右两侧是基本类型变量,比较的是变量中值是否相同
b.如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同
c.如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的
重写equals方法
参考代码:
class Person{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if(obj==null){
return false;
}
if(obj==this){
return true;
}
if(!(obj instanceof Person)){
return false;
}
Person person=(Person) obj;
return this.name.equals(person.name)&&this.age== person.age;
}
}
public class T1 {
public static void main(String[] args) {
Person person1=new Person("张三",28);
Person person2=new Person("王五",28);
Person person3=new Person("王五",28);
System.out.println(person1.equals(person1));
System.out.println(person1.equals(person2));
System.out.println(person2.equals(person3));
}
4.Clonable 接口
平时对数组进行拷贝时,可以直接调用copyof方法和clone方法
public static void main(String[] args) {
int []arr={1,2,3,4,5,6,7};
int []brr=arr.clone();
int []crr=Arrays.copyOf(arr,arr.length);
System.out.println(Arrays.toString(brr));
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(crr));
}
但是在对一个对象进行拷贝时,却无法使用copyof方法和直接使用clone方法
故此就需要用到Clonable接口
4.1Clonable的使用
注意事项:
1.当以上4步均为实现时,直接调用clone方法时
编译器会报这样的错误
这是因为Object类的clone方法是被protected所修饰的,只能在同一个包或不同包的子类中访问,然而我的测试类显然和Object类没关系
解决办法:
在Sheep类重写Object类的clone方法,调用Object类的clone方法
2.当重写玩clone方法后还报错
这是因为重写的clone方法的返回值是Object类型,子类不能接收父类对象,我们需要向下转型,将返回值强转为Sheep类型
3.当一个自定义的类型想要被克隆,就必须实现Cloneable接口
然而,这个Cloneable接口是一个空接口
空接口也叫做标记接口,实现了这个接口就表示当前类是可以被复制的
4.完成以上操作报异常
处理一下异常就可以了
4.2浅拷贝VS深拷贝
浅拷贝:
运行下面代码有什么意外
class Price{
int price;
}
class Sheep implements Cloneable{
String name;
int age;
Price price=new Price();
public Sheep(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "{name:"+this.name+" age:"+this.age+"price:"+this.price.price+"}";
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class T1 {
public static void main(String[] args)throws CloneNotSupportedException {
Sheep sheep1=new Sheep("多莉",2);
sheep1.price.price=99;
Sheep sheep2=(Sheep) sheep1.clone();
sheep2.price.price=88;
System.out.println(sheep1.toString());
System.out.println(sheep2.toString());
}
}
当输出结果是,会发现sheep1和sheep2的price都变成了88,然而我并没有操作sheep1的price,这是因为在克隆是我克隆的只是price的地址,所以sheep1和sheep2的price指向的是同一块空间,当操作sheep2的price时,也就相当于操作了sheep1的price
以上就是浅拷贝,也就是说浅拷贝不能拷贝类里面的其他对象,只能拷贝对象的地址
深拷贝:
深拷贝也就是将对象也进行拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep tmp=(Sheep) super.clone();
tmp.price= (Price) this.price.clone();
return tmp;
}
我们只需要将sheep1的price克隆,然后被指向sheep2的price
注意事项:
1.在对price进行克隆时,需要先在price类里面实现Cloneable接口,并重写clone方法
2.tmp在将克隆的结果返回出来后,会被销毁
3.注意向上转型和向下转型