comparable接口只是一个引子,引出策略模式中的接口comparator接口
comparable接口的演变思想还是有价值去研究的
一.comparable接口演变
演变一:
这一版本中运用选择排序实现了一个int类型最基本的排序功能
1 public class Sorter { 2 3 public static void sort(int[] arr) { 4 for (int i=0; i<arr.length - 1; i++){ 5 int minPoint = i; 6 7 for(int j=i+1; j<arr.length; j++){ 8 minPoint = arr[j] < arr[minPoint] ? j : minPoint; 9 } 10 11 swap(arr, i, minPoint); 12 } 13 } 14 15 static void swap(int[] arr, int i , int j){ 16 int temp = arr[i]; 17 arr[i] = arr[j]; 18 arr[j] = temp; 19 } 20 }
1 public class Main { 2 public static void main(String[] args) { 3 int[] a = {9,2,3,5,7,1,4}; 4 Sorter sorter = new Sorter(); 5 sorter.sort(a); 6 System.out.println(Arrays.toString(a)); 7 } 8 }
问一:如果要对float类型的数字进行排序怎么办?对double类型、byte类型呢?
答:只需要在Sorter类中重写sort方法就能实现
问二:如果要对一些引用数据类型进行排序呢?
答:这一版本肯定是不行的
演变二:
接问题二进而有了第二个版本,针对引用数据类型进行排序,我们这里举例Cat
那么怎么比较猫的大小呢?这里就需要我们编写方法规定好比较规则了(CompareTo方法)
1 public class Cat { 2 int weight,height; 3 4 public Cat(int weight,int height){ 5 this.weight = weight; 6 this.height = height; 7 } 8 9 public int compareTo(Cat cat){ 10 if (this.weight < cat.weight) return -1; 11 else if(this.weight > cat.weight) return 1; 12 else return 0; 13 } 14 15 @Override 16 public String toString() { 17 return "Cat{" + 18 "weight=" + weight + 19 ", height=" + height + 20 '}'; 21 } 22 }
1 public class Sorter { 2 3 public static void sort(Cat[] arr) { 4 for (int i=0; i<arr.length - 1; i++){ 5 int minPoint = i; 6 7 for(int j=i+1; j<arr.length; j++){ 8 minPoint = arr[j].compareTo( arr[minPoint] ) == -1 ? j : minPoint; 9 } 10 swap(arr, i, minPoint); 11 } 12 } 13 14 static void swap(Cat[] arr, int i , int j){ 15 Cat temp = arr[i]; 16 arr[i] = arr[j]; 17 arr[j] = temp; 18 } 19 }
1 public class Main { 2 public static void main(String[] args) { 3 Cat[] cat = {new Cat(3,3), new Cat(5,5), new Cat(1,1)}; 4 Sorter sorter = new Sorter(); 5 sorter.sort(cat); 6 System.out.println(Arrays.toString(cat)); 7 } 8 }
问三:这个版本中我们对Cat类进行了排序,那么如果我要对Dog类、Egg类进行排序怎么办?
答:我们可以将Sorter类中传入sort方法的参数类型设置为Object类型
问四:解决了上面问三,但是Object类中并没有compareTo方法怎么办?
答:可以新建一个接口,里面定义compareTo方法,所有参与比较的类都要实现该接口
演变三:
解决问三、问四问题
1 public interface Comparable { 2 //为了实现多个类共用此方法,这里将传入参数设置为Object类型 3 public int compareTo(Object o); 4 }
1 public class Sorter { 2 //为了实现共用,而将传入参数设置为Comparable 3 public static void sort(Comparable[] arr) { 4 for (int i=0; i<arr.length - 1; i++){ 5 int minPoint = i; 6 7 for(int j=i+1; j<arr.length; j++){ 8 minPoint = arr[j].compareTo( arr[minPoint] ) == -1 ? j : minPoint; 9 } 10 swap(arr, i, minPoint); 11 } 12 } 13 14 static void swap(Comparable[] arr, int i , int j){ 15 Comparable temp = arr[i]; 16 arr[i] = arr[j]; 17 arr[j] = temp; 18 } 19 }
1 public class Dog implements Comparable { 2 3 int food; 4 5 public Dog(int food){ 6 this.food = food; 7 } 8 9 //这里传入参数为Object类型 10 @Override 11 public int compareTo(Object o) { 12 //这里要使用Dog类型进行转换时,需要将Object类型的参数转换为Dog类型 13 Dog dog = (Dog)o; 14 if (this.food<dog.food) return -1; 15 else if (this.food<dog.food) return 1; 16 else return 0; 17 } 18 19 @Override 20 public String toString() { 21 return "Dog{" + 22 "food=" + food + 23 '}'; 24 } 25 }
1 public class Cat implements Comparable{ 2 int weight,height; 3 4 public Cat(int weight,int height){ 5 this.weight = weight; 6 this.height = height; 7 } 8 9 //这里传入参数为Object类型 10 public int compareTo(Object o){ 11 //这里要使用Cat类型进行转换时,需要将Object类型的参数转换为Cat类型 12 Cat cat = (Cat)o; 13 if (this.weight < cat.weight) return -1; 14 else if(this.weight > cat.weight) return 1; 15 else return 0; 16 } 17 18 @Override 19 public String toString() { 20 return "Cat{" + 21 "weight=" + weight + 22 ", height=" + height + 23 '}'; 24 } 25 }
1 public class Main { 2 public static void main(String[] args) { 3 Dog[] dogs = {new Dog(3), new Dog(5), new Dog(1)}; 4 Sorter sorter = new Sorter(); 5 sorter.sort(dogs); 6 System.out.println(Arrays.toString(dogs)); 7 } 8 }
问五:如果比较对象与被比较对象类型不相同,那么传入参数进行强制转换时就会报错
答:利用java中泛型在演变三基础上进行修改
演变四:
在上一个版本基础上利用泛型进行代码修改
仅展示部分修改后代码,未修改的部分参照演变三中代码
1 //加上泛型,更加灵活 2 public interface Comparable<T> { 3 //不必设置为Object类型 4 public int compareTo(T o); 5 }
1 //实现接口时传入泛型 2 public class Dog implements Comparable<Dog> { 3 4 int food; 5 6 public Dog(int food){ 7 this.food = food; 8 } 9 10 //实现接口中方法,将传入参数确定比较类型 11 @Override 12 public int compareTo(Dog dog) { 13 //增加泛型后这里减少了强制转换带来的隐患 14 if (this.food<dog.food) return -1; 15 else if (this.food<dog.food) return 1; 16 else return 0; 17 } 18 19 @Override 20 public String toString() { 21 return "Dog{" + 22 "food=" + food + 23 '}'; 24 } 25 }
演变五:
最完美的结果就是实现java中自带的comparable接口
二.comparator接口
接着上面comparable接口,在猫这个实体类在comparable接口中的比较策略是通过比较体重来进行判断的。但是,实际生活中比较猫可以通过很多方面,如体重、身高、身长等。那么怎样实现猫比较大小的策略可以灵活指定呢?
这里在解决上述问题时将原本的一个泛型变为两个泛型,第一个泛型为比较的数组,第二个泛型为打比较的策略。如果需要添加新的比较策略,只需在新建类中定义具体比较策略并实现相应接口,在需要调用时利用多态new出不同实现类即可实现不同方式的比较策略
1 public interface Comparator<T> { 2 //定义两个泛型,第一个为比较数组,第二个为比较策略 3 public int compare(T o1,T o2); 4 }
1 /** 2 * 狗的比较器 3 * 具体实现类,定义狗的具体比较策略 4 */ 5 public class DogComparator implements Comparator<Dog> { 6 @Override 7 public int compare(Dog o1, Dog o2) { 8 if (o1.food<o2.food) return -1; 9 else if (o1.food>o2.food) return 1; 10 else return 0; 11 } 12 }
1 public class Sorter<T> { 2 /** 3 * 比较方法在调用时需要传入两个参数 4 * 第一个参数为需要参与比较的数组,数组中存放n个狗的对象 5 * 第二个参数为狗进行比较时的具体比较策略,这个根据具体需求利用多态new出来即可 6 */ 7 public void sort(T[] arr,Comparator<T> comparator) { 8 for (int i=0; i<arr.length - 1; i++){ 9 10 int minPoint = i; 11 12 for(int j=i+1; j<arr.length; j++){ 13 minPoint = comparator.compare(arr[j], arr[minPoint] ) == -1 ? j : minPoint; 14 } 15 swap(arr, i, minPoint); 16 } 17 } 18 19 void swap(T[] arr, int i , int j){ 20 T temp = arr[i]; 21 arr[i] = arr[j]; 22 arr[j] = temp; 23 } 24 }
1 public class Dog { 2 3 int food; 4 5 public Dog(int food){ 6 this.food = food; 7 } 8 9 @Override 10 public String toString() { 11 return "Dog{" + 12 "food=" + food + 13 '}'; 14 } 15 }
1 public class Main { 2 public static void main(String[] args) { 3 Dog[] dogs = {new Dog(3), new Dog(5), new Dog(1)}; 4 Sorter sorter = new Sorter(); 5 sorter.sort(dogs,new DogComparator()); 6 System.out.println(Arrays.toString(dogs)); 7 } 8 }