介绍两个接口
下面将会介绍到:Comparable
接口和 Cloneable
这两个接口;
Comparable接口
重新认识sort()方法
要求
:给对象数组进行排序
说到排序,我们就能想到之前所学的Arrays.Sort()
方法,那接下来我们就来看一下该方法能否成功对对象数组进行排序呢?往下看
:
(1) 定义一个学生类
先对整形数组进行一个排序,结果如下:
import java.util.Arrays;
public class Student {
public static void main(String[] args) {
// 定义一个整形数组
int[] array1={2,3,1,5,6,8,7,4,9,0};
Arrays.sort(array1);
for(int i=0;i<array1.length;i++){
System.out.print(array1[i]+" ");
}
System.out.println();
}
}
运行结果:
0 1 2 3 4 5 6 7 8 9
由上看出
:得到的结果跟我们的预期是一样的!
那接下来我们就用该方法对学生对象进行排序~~
示例如下:
import java.util.Arrays;
public class Student {
private String name;
int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public static void main(String[] args) {
Student[] array2={new Student("张三",87),
new Student("李四",89),
new Student("王五",67),
new Student("赵六",79)};
Arrays.sort(array2);
for(int i=0;i<array2.length;i++){
System.out.println(array2[i]);
}
}
}
那结果跟我们想象的并不一致,不但没有排出结果,还报错了,报错信息如下:
那我们就来分析一下,为什么会报错呢?
原因:由于学生信息里面有多个字段,既有名字,又有成绩,采用sort()
进行排序时,编译器并不知道依据什么来进行排序,因此会报错;也就是说,sort()
并不能直接对自定义对象直接进行排序呢.
那如果我们还想用该方法进行排序,那怎么实现呢?请往下看:
实现的前提
:保证学生对象是可以进行比较的,才能进行排序;
实现
:Java
为我们提供了一个Comparable
接口,只要实现这里面的compareTo()
抽象方法,即可进行排序了;
代码如下:
import java.util.Arrays;
public class Student implements Comparable {
private String name;
int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public int compareTo(Object o) {
Student s = (Student) o;
//this : 表示当前对象
//o: 表示要和this比较的对象
if (score > s.score) {
return 1; // 1代表正的
} else if (score < s.score) {
return -1;
} else {
return 0;
}
}
public static void main(String[] args) {
Student[] array2 = {new Student("张三", 87),
new Student("李四", 89),
new Student("王五", 67),
new Student("赵六", 79)};
Arrays.sort(array2);
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i]);
}
}
}
结果:
day20211001.Student@1b6d3586
day20211001.Student@4554617c
day20211001.Student@74a14482
day20211001.Student@1540e19d
运行后,虽然没有报错,但结果还是跟我们预想的不一样,打印的并不是不是对象中的内容,而是这样一串类似地址的值,那是因为在打印时,会调用Object
类中的toString()
方法,所以需要重写该方法;
**重写
toString()`方法**
@Override
public String toString() {
String s=new String("[");
s+=name;
s+=",";
s+=score;
s+="]";
return s;
}
重写完成之后,再运行,就可以看到我们想要的结果了,如下所示:
[王五,67]
[赵六,79]
[张三,87]
[李四,89]
由上面我们会发现,编译器是按照升序的顺序给我们进行打印的,如果想要降序进行排列,只需要将上面compareTo()
方法下的正负1互相倒换一下即可;
以上都是Java系统给我们提供的sort()
方法,接下来模拟实现sort()
方法;
如下所示:采用之前所写的冒泡排序法
,让能够实现Comparable
接口的的,都可以进行排序;
思路
:用外层循环控制冒泡的趟数,里层循环控制冒泡的方式;
public class Student implements Comparable {
private String name;
int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public int compareTo(Object o) {
Student s = (Student) o;
//this : 表示当前对象
//o: 表示要和this比较的对象
if (score > s.score) {
return 1; // 1代表正的
} else if (score < s.score) {
return -1;
} else {
return 0;
}
}
public static void sort(Comparable[] stu){
for(int i=0;i<stu.length-1;i++){
for(int j=0;j<stu.length-i-1;j++){
//比较的方式:compareTo()
if(stu[j].compareTo(stu[j+1])>0){
Comparable temp=stu[j];
stu[j]=stu[j+1];
stu[j+1]=temp;
}
}
}
}
@Override
public String toString() {
String s=new String("[");
s+=name;
s+=",";
s+=score;
s+="]";
return s;
}
public static void main(String[] args) {
Student[] array2 = {new Student("张三", 87),
new Student("李四", 89),
new Student("王五", 67),
new Student("赵六", 79)};
//Arrays.sort(array2);
Student.sort(array2);
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i]);
}
}
}
然后,调用 Student.sort(array2);
同样可以看到与上面相同的输出结果;
[王五,67]
[赵六,79]
[张三,87]
[李四,89]
(1)上面代码中的一个逻辑关系就是
Student
类重写了Comparable
中的compareTo
抽象方法;
(2)要想打印对象中的内容,就要调用Object
类中的toString()
方法;
(3)涉及到的Object
类,是所有类的一个基类(可以通过IDEA去查看);
注意两个点:
利用sort方法对自定义类型对象进行排序时:
(1)需要先实现Comparable
接口;
(2)在该类中需要重写Comparable
中的compareTo
抽象方法;
Cloneable 接口
认识深浅拷贝(只针对自定义类型)
完成对象与对象之间的拷贝:
Cloneable
接口
拷贝简单可以分为两种:
(1)浅拷贝
:拷贝引用,不拷贝内容
new
一个s1
学生对象,然后再new
一个s2
对象,并将s1
指向s2
,简单来说,其实就是将s1
的引用赋给了s2
,使两个对象指向同一个内存空间,也就是使两个引用变量实际引用的是同一份对象;
**注意**
:没有拷贝对象的内容(name,score),只是拷贝了引用;
public static void main(String[] args) {
Student s1 =new Student("张三",90);
Student s2=s1;
导致的后果:
当一个人的成绩被修改之后,另一个人的成绩也随之被更改了;
public static void main(String[] args) {
Student s1 =new Student("张三",90);
Student s2=s1;
s1.score=99;
System.out.println(s2);
}
运行结果:
[张三,99]
浅拷贝存在这样的问题,那要改变这种不想要的结果,所以就需要研究深拷贝了,接下来看一下
深拷贝;
(2)深拷贝
:将实际对象中的内容拷贝了一份,行成一个新的对象;
谈到深拷贝,就需要讨论Cloneable
这个接口了;
(1)
Cloneable
接口的使用
首先,定义一个Person
类,让该类去实现Cloneable
这个接口;然后,使用快捷键crtl+左键
,进入到该方法体中,但发现里面并没有任何的抽象方法;对于之前的理解,接口就是一个规范,既然里面没有抽象方法,那我们就不用实现它;
Cloneable
接口里面:
(2)对
Clone()
方法进行重写(crtl+o)
上面已经说了,Object
类是所有类的一个基类,该类中存在一个 clone()
方法, 调用该方法就可以拷贝一个对象的,使用crtl+o
进行重写,但重写完成之后,还需要改动三个地方:
第一,将修饰权限改为public
;
原因
:因为重写的目的就是为了在类外进行调用,所以,需要修改权限修饰符;
第二,将类名Object改为本类名称;
原因
:clone()方法被Person类重写了,拷贝出来的对象是一个Person对象;
第三,将返回值类型强制转换为本类类型;
修改之后结果如下:
@Override
public Person clone() throws CloneNotSupportedException {
return (Person)super.clone();
}
(3)调试运行整个代码
public class Person {
private String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public Person clone() throws CloneNotSupportedException {
return (Person)super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 =new Person("lilei",19);
Person p2=p1;
p2.age=20;
System.out.println(p1.age);
Person p3=p1.clone();
p3.age=21;
System.out.println(p1.age);
System.out.println(p2.age);
System.out.println(p3.age);;
}
}
我们会发现:该段代码会抛出异常信息,异常信息如下:那为什么会这样呢?
原因其实很简单:就是没有实现Cloneable
接口,虽然它里面没有抽象方法,但在这里相当于是一个标志,实现了它,代码就可以正常运行了;
public class Person implements Cloneable{
// 下面均是相同的
但会发现运行调试之后,对象里面的内容并没有发生改变,因此这种方式仍然是浅拷贝;结果如下:
也就是说,直接使用clone()
这个方法,并不能实现深拷贝,那要怎么样实现深拷贝呢?其实也不难,就是要将该类中的引用类型一层一层的实现cloneable
接口并重写clone()
方法,直到最后只剩下基本类型,就实现深拷贝了。
代码如下:
class Money implements Cloneable{
double d=12.34;
@Override
public Money clone() throws CloneNotSupportedException {
return (Money)super.clone();
}
}
public class Test implements Cloneable{
int num;
Money m;
public Test(){
num=100;
m=new Money();
}
@Override
public Test clone() throws CloneNotSupportedException {
Test t=(Test)super.clone();
t.m=m.clone();
return t;
}
public static void main(String[] args) throws CloneNotSupportedException {
Test t1=new Test();
Test t2=t1.clone();
t1.m.d=100;
}
}
调试运行,就可以看到如下结果,这样才真正实现了深拷贝;
仔细体会》
想要各位大佬给个宝贵的意见
,共勉~~