java的comparable接口,java的comparator接口

  java的comparable接口,java的comparator接口

  00-10101.Compable 2。比较器3。可克隆界面和深层拷贝

  00-1010这个接口用于对一个对象数组进行排序

  在我学习接口之前,我使用的排序方法是Arrays.sort()。我发现对象数组排序的问题,仅靠之前学的东西是解决不了的。后来发现Comparable的接口解决了我的疑惑,感受到了这个接口的强大,但不是最好的。后面会说,学习知识毕竟是一个循序渐进的过程。

  首先,让我们看一下我们在之前的研究中使用的Arrays.sort。

  public class test demo { public static void main(String[]args){ int[]array={ 1,3,6,2,4 };Arrays.sort(数组);system . out . println(arrays . tostring(array));}}它可以对整数数组从小到大排序、我们来看看Arrays.sort排序对象数组(错误演示)

  class Student {公共字符串名称;公共int age公开双分;public Student(String name,int age,double score){ this . name=name;this.age=年龄;this.score=score} @ Override public String to String(){ return Student { name= name ,age= age ,score= score }} } public class test demo { public static void main(String[]args){ Student[]students=new Student[3];学生[0]=新生(张三,98,78.9);学生[1]=新生( lisi ,38,48.9);学生[2]=新生(吴王,18,88.9);Arrays.sort(学生);system . out . println(arrays . tostring(学生));}}当我们编写这样的代码时,会发现运行结果是什么?马鞭

  这个时候不要慌。简单分析一下错误的原因。我们可以看到它报告了一个ClassCastException(类型转换异常)。根据下面能稍微听懂的英语(边肖本人英语水平太差,只能听懂几个),我们大概可以知道,Student是无法转换成java.lang包下的Comparable的。这个时候,我们就点进去看看源代码吧。不要害怕阅读源代码。有时候我们只需要理解一个。

  在粗略分析了line if条件语句后,我们发现数组被标记为down,并且用compareTo对元素进行了相互比较。这时,我们发现了其中的猫腻。我们打开帮助手册查看compare,发现是一个泛型接口,而且有一个抽象方法compareTo。这时,面纱就会被一层一层揭开。

  看到compareTo方法中这个大图的第一行,我们就明白了。这个东西可以帮助我们解决比较数组对象的问题,所以我们要带class Student实现Comparable,实现compareTo方法,这样就可以对数组对象进行排序。看看代码:

  class Student实现comparable Student { public String name;公共int age公开双分;public Student(String name,int age,double score){ this . name=name;

   this.age = age; this.score = score; } @Override public String toString() { return "Student{" + "name=" + name + + ", age=" + age + ", score=" + score + }; } @Override public int compareTo(Student o) { //return this.name.compareTo(o.name); //return this.age - o.age; return (int)(this.score-o.score); }}这时候Arrays.sort()就可以帮我们做到对象数组的排序了,在 sort 方法中会自动调用 compareTo 方法. compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.

  然后比较当前对象和参数对象的大小关系 (例如按score ).

  如果当前对象应排在参数对象之前 , 返回小于 0 的数字 ;如果当前对象应排在参数对象之后 , 返回大于 0 的数字;如果当前对象和参数对象不分先后 , 返回 0;如果你对姓名的比较存在疑惑,比如:为什么name也可以调用compareTo方法这种类似的问题,因为name是String类型的,我建议你先看一下String的源码,里面也实现了Comparable接口,以及重写了compareTo方法,这里就不详细介绍了,感兴趣的小伙伴们可以尝试一下哦,当然,我相信你们都是大佬,一看就懂哈哈

  执行程序,看运行结果,这下就能达到我们想要的效果了

  

 

  前面说了,这样的代码也不是最好的,存在局限性,我按分数来排序,那代码就写死了 ,那我以后想按姓名来排序,我又得回头改???,以后进公司了,你的代码做改变,影响其他人的代码,那不得把你骂死,所以我们需要做进一步改进,引入Comparator接口

  

 

  

2.Comparator比较器

这个接口又叫比较器,那比较器又是个什么东西呢???下面我也是老套路啦,一步一步揭开这东西的面纱

 

  为了解决Comparable接口的局限性,我们这个比较器完美的展现了实现效果,它也是一个泛型接口,同样只有一个抽象方法需要重写,下面看代码:

  

class Student { public String name; public int age; public double score; public Student(String name, int age, double score) { this.name = name; this.age = age; this.score = score; } @Override public String toString() { return "Student{" + "name=" + name +  + ", age=" + age + ", score=" + score + }; }}//比较器class AgeComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return o1.age - o2.age; }}class StringComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return o1.name.compareTo(o2.name); }}class ScoreComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return (int)(o1.score-o2.score); }}public class TestDemo { public static void main(String[] args) { Student[] students = new Student[3]; students[0] = new Student("zhangsan",98,78.9); students[1] = new Student("lisi",38,48.9); students[2] = new Student("wangwu",18,88.9); /*AgeComparator ageComparator = new AgeComparator(); Arrays.sort(students,ageComparator); StringComparator stringComparator = new StringComparator(); Arrays.sort(students,stringComparator);*/ ScoreComparator scoreComparator = new ScoreComparator(); Arrays.sort(students,scoreComparator); System.out.println(Arrays.toString(students)); }}

通过这段代码,我们发现比较器是真真正正的做到了,想按什么排序就按什么排序,在对类的侵入性以及代码耦合度方面也算是不用太过担心了

 

  

 

  

3.Clonable接口和深拷贝

Java 中内置了一些很有用的接口 , Clonable 就是其中之一 .

 

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

  先来看一段代码吧,我个人喜欢结合代码看分析,这样子就降低了云里雾里的可能性了,

  

class Student implements Cloneable{ public int id = 1234; @Override public String toString() { return "Student{" + "id=" + id + }; } //重写Object父类的clone()方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }}public class TestDemo { public static void main(String[] args) { Student student1 = new Student(); try { Student student2 = (Student) student1.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } }}

实现克隆的两个条件(结合上面代码):

 

  1.这个对象可以被克隆,也就是这个Student类要实现这个Clonable接口

  2.要在这个类中重写父类Object的clone()方法

  

 

  我们现在的代码只是达到了这样一个效果,,重头戏还在后边,因为我们的拷贝有时候远远不止于此,这种只能算是一个浅拷贝,那什么才算是深拷贝呢??? 请看下面的代码:

  

class Money implements Cloneable{ public double money = 19.9; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }}class Student implements Cloneable{ public int id = 1234; public Money m = new Money(); @Override public String toString() { return "Student{" + "id=" + id + }; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }}public class TestDemo { public static void main(String[] args) throws CloneNotSupportedException { Student student1 = new Student(); //为了代码的好看,我这里不处理这个异常 Student student2 = (Student) student1.clone(); System.out.println(student1.m.money); System.out.println(student2.m.money); System.out.println("========================="); student1.m.money = 99.99; System.out.println(student1.m.money); System.out.println(student2.m.money); }}

我现在在之前的代码的基础上添加了一个Money类,并且实例化Money的对象作为Student的成员,这时候克隆之后,改变我money的值,会是一个什么的效果呢???

 

  先看运行结果吧,我就不兜圈子了

  

 

  我们发现,这并不是我们想要的结果,我们想要的结果是,通过student2去改变money的值,它并不会影响student1中的money,而我们刚刚的代码并没有做到,它的效果图如下:

  

 

  那又如何做到深拷贝呢??这时我们就需要对我们刚才的代码做一些改进了

  我们只需将原来的Student类中的Object的克隆方法改成下面这份代码就能做到我们想要的效果:

  

@Override protected Object clone() throws CloneNotSupportedException { Student tmp = (Student) super.clone();//将id变量克隆一份,tmp指向它 tmp.m = (Money) this.m.clone();//将m对象中的money变量克隆一份 tmp中的m指向它 return tmp; //return super.clone(); }

看到这个代码先不要慌,如果注释没看明白,咱还有板书可以参照

 

  其实分析起来也就那么回事

  

 

  当我们tmp返回的时候,就把0x99给到了student2,克隆完成之后,tmp是局部变量,也就被回收了,,,就变成了下面这副摸样:

  

 

  这个时候,我们再去通过student2去改变我们的money,就不会影响student1中的money的值了,废话不多说,运行结果为证

  

 

  以上就是三个重要接口的全部分析了,下次再见!!!

  到此这篇关于深入分析Comparable与Comparator及Clonable三个Java接口的文章就介绍到这了,更多相关Java Comparable Comparator Clonable内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: