1.comparable接口
将学生类实现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 +
'}';
}
}
public class Test {
public static void main(String[] args) {
Student[] student = new Student[3];
student[0] = new Student("zhangsan",16);
student[1] = new Student("lisi",8);
student[2] = new Student("wangwu",10);
Arrays.sort(student);
System.out.println(Arrays.toString(student));
}
}
现在我们来刨析一下上面的代码,因为我们用调用Arrays.sort()方法来对student数组进行排序,但是但是在Arrays.sort()方法底层是要调用我们的compareTo方法的 ,所以我们要对我们的类数组进行排序时,就要使用comparable接口里面的功能,所以要实现comparable的接口。如果说我们要通过姓名来对该数组进行排序的话,就要将compareTo()方法改掉。如下:
public int compareTo(Student o) {
return this.name.compareTo(o.name);
}
但是comparable接口里面的方法,一旦写好就不能轻易去改动,那么我们在想有没有一种办法来做到我们想用什么来对数组进行排序就用什么呢?那么我们就来介绍一下下面这个接口。
2.Comparator接口(比较器比较)
这里我们可以通过Comparator接口来写两个比较器,来实现我们想用什么来进行排序就用什么来进行排序。
import java.util.Arrays;
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 +
'}';
}
}
public class Test {
public static void main(String[] args) {
Student[] student = new Student[3];
student[0] = new Student("zhangsan",10);
student[1] = new Student("lisi",5);
student[2] = new Student("abc",15);
AgeComparator ageComparator = new AgeComparator();
Arrays.sort(student,ageComparator);
System.out.println(Arrays.toString(student));
}
}
上面我们使用了Comparator接口实现了年龄比较器,现在我们再实现一个姓名比较器用来对Student数组进行姓名排序。
public class Test {
public static void main(String[] args) {
Student[] student = new Student[3];
student[0] = new Student("zhangsan",10);
student[1] = new Student("lisi",5);
student[2] = new Student("abc",15);
/*AgeComparator ageComparator = new AgeComparator();
Arrays.sort(student,ageComparator);*/
NameComparator nameComparator = new NameComparator();
Arrays.sort(student,nameComparator);
System.out.println(Arrays.toString(student));
}
}
通过上面的代码我们应该初步明白了Comparator接口的作用,就是通过比较器来实现接口进而使比较器具备了比较的功能。方便了我们对类数组的排序操作。
3.Clonable接口和浅拷贝及深拷贝介绍
Java 中内置了一些很有用的接口, Clonable 就是其中之一. Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝". 但是要想合法调用 clone 方法, 必须要 先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常。那么我们下面就来用这个接口写一些代码:
class Student implements Cloneable{
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 +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}//因为该类本身没有clone方法,所以要调用Object类中的clone方法,那么我们就要重写Object类中的clone方法。
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException{
Student student1 = new Student("小明",18);
Student student2 = (Student)student1.clone();
student2.age = 10;
System.out.println(student1.age);
System.out.println(student2.age);
}
}
可见修改了student2中的age并没有影响,student1中的age所以说我们就成功的将student1指向的对象克隆了。
下面我们来聊一聊浅拷贝和深拷贝的问题:我们看下面代码:
class Money {
public double m = 12.5;
}
class Student extends Money implements Cloneable{
String name;
int age;
public Money money = new Money();
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}//因为该类本身没有clone方法,所以要调用Object类中的clone方法,那么我们就要重写Object类中的clone方法。
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException{
Student student1 = new Student("小明",18);
Student student2 = (Student)student1.clone();
student2.money.m= 10.0;
System.out.println(student1.money.m);
System.out.println(student2.money.m);
}
}
我们可以看到当我们通过student2来修改m时,student1中的m也被改了,所以这种现象的发生就叫浅拷贝,下面我们看内存图来理解一下浅拷贝的实现:
可以看到m并没有克隆,money还是指向原来的m那么我们就在想是不是能将m也克隆一份,然后将student2中的money指向克隆后的m。下面我们对代码进行一些改进:
class Money implements Cloneable {
public double m = 12.5;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Student extends Money implements Cloneable{
String name;
int age;
public Money money = new Money();
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student tmp = (Student) super.clone();
tmp.money =(Money) this.money.clone();
return tmp;
}//因为该类本身没有clone方法,所以要调用Object类中的clone方法,那么我们就要重写Object类中的clone方法。
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException{
Student student1 = new Student("小明",18);
Student student2 = (Student)student1.clone();
student2.money.m= 10.0;
System.out.println(student1.money.m);
System.out.println(student2.money.m);
}
}
从上面的代码可以看到这里在通过student2来修改m的值时,student1中的m就不被改了,这就实现了我们的深拷贝。 我们可以通过下面的图来理解一下深拷贝的实现: