初识java——javaSE (6)接口的实现——比较器与深拷贝,浅拷贝


前言


上一篇博客并没有将接口的内容阐述完毕,这篇博客继续阐述!

一 比较器

1.1 关于两个对象的比较

在比较单个基本数据类型时,我们可以通过关系运算符进行比较。
 public class Test {
   
        public static void main(String[] args) {
            int age1 = 10;
            int age2 = 8;
            System.out.println(age1 > age2);
           }

在这里插入图片描述

但是当比较对象等引用数据类型时,便不能仅仅通过关系运算符进行比较了。
class Student {
    String name;
    int age;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }
  }
     public class Test {
               public static void main(String[] args) {

            Student student1 = new Student(10,"张三");
            Student student2 = new Student(12,"李四");
            System.out.println(student1>student2);

     }
   
    }

在这里插入图片描述

要进行对象间的比较,需要确定进行比较的规则是什么,比较哪一个属性。

1.2 Comparable接口:

Comparable接口中的compareTo 方法用于进行对象间属性的比较。

在这里插入图片描述
compareTo是一个抽象方法,我们需要重写:

//创建一个Student类,实现Comparable接口
class Student implements Comparable<Student> {
    String name;
    int age;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
//重写compareTo方法
    @Override
    public int compareTo(Student o) {
        //比较年龄:

        if(this.age == o.age){
            return 0;
        }else if(this.age>o.age){
            return 1;
        }else {
            return -1;
        }
    }
        //比较姓名
      //  return this.name.compareTo(o.name);
    }

    public class Test {
  
        public static void main(String[] args) {

            Student student1 = new Student(10,"张三");
            Student student2 = new Student(12,"李四");
            System.out.println(student1.compareTo(student2));

在这里插入图片描述
结果为-1 ,表明student1的年龄比student2的年龄小。
代码分析:
Student类实现了Comparable接口,
<>是泛型的标记,以后会阐述到,比较那个类,就将类名填写在<>中!

对象间的比较本质上依然是对象属性之间的比较。

1.3 Arrays.sort方法的实现

如果创建一个对象数组,使得数组中的这些对象按照某种规则进行排序
则可以使用Array.sort方法

class Student implements Comparable<Student> {
    String name;
    int age;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    @Override
    public int compareTo(Student o) {
        //比较年龄:

        if(this.age == o.age){
            return 0;
        }else if(this.age>o.age){
            return 1;
        }else {
            return -1;
        }
    }
        //比较姓名
      //  return this.name.compareTo(o.name);
    }

  public class Test {
  public static void main(String[] args) {
            Student[] arr1 = new Student[3];
            arr1[0] = new Student(10, "王五");
            arr1[1] = new Student(8, "李四");
            arr1[2] = new Student(9, "张三");
                Student[] arr1 = {student1,student2,student3};
            System.out.println("排序前:"+Arrays.toString(arr1));
            
            Arrays.sort(arr1);
            System.out.println("排序后:"+Arrays.toString(arr1));
          
     }
}

在这里插入图片描述
排序后,年龄从小到大,依次递增。

如果不实现Comparable接口,会怎么样呢?
在这里插入图片描述
在这里插入图片描述
结果表明Student类型,不能转换成Comparable类型,这是怎么回事,我们调用Arrays.sort方法进行排序,与转换类型有什么关系?

这里我们需要手动实现一下Arrays.sort方法

 public  static  void mysort(Comparable[] comparables){
        // 用接口数组接收实现接口的数组   采用冒号排序的方式
        //比较的趟数!
        for (int i = 0;i<comparables.length-1 ;i++){
              for (int j = 0; j<comparables.length - 1-i;j++){
              
                  if(comparables[j].compareTo(comparables[j+1])>0){
                       //如果数组前面元素的值大于数组后面元素的值,则交换引用的值,这是升序
                      Comparable tmp  = comparables[j];
                      comparables[j]  = comparables[j+1];
                      comparables[j+1] = tmp;
                  }
              }

        }
    }

代码分析: 问题就在于 if(comparables[j].compareTo(comparables[j+1])>0) 这条语句
我们通过接口类型数组来接收实现了接口的数组,并且对compareTo方法进行调用!

在上个例子中,因为没有Student没有实现Comparable接口,所以会发生Student类型无法发生向上转型成Comparable接口类型的情况。

调用自己实现的mysort方法:

class Student implements Comparable<Student> {
    String name;
    int age;
    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public int compareTo(Student o) {
        //比较年龄:

        if(this.age == o.age){
            return 0;
        }else if(this.age>o.age){
            return 1;
        }else {
            return -1;
        }
    }
        //比较姓名
      //  return this.name.compareTo(o.name);
    }
    public class Test {


  public static void main(String[] args) {

       
            Student[] arr1 = new Student[3];


            arr1[0] = new Student(10, "王五");
            arr1[1] = new Student(8, "李四");
            arr1[2] = new Student(9, "张三");
         
            System.out.println("排序前:" + Arrays.toString(arr1));
           
              mysort(arr1);
            System.out.println("排序后:" + Arrays.toString(arr1));
           

        }
    }

在这里插入图片描述

1.4 比较器的实现

在上面实现compareTo方法时,我们只能比较某一固定的属性,比如年龄或者名字,
这比较有局限性,总不能当需要比较某一属性时,再去修改类的实现。

解决方案:当需要比较某一属性时,就调用相关的类!

Comparator接口

在这里插入图片描述
如图所示:Comparator接口中有一个compare抽象方法。
我们可以创建不同的类来实现此接口,当需要比较不同的属性值时,调用不同的类:

举例:

//在单独一个java文件中
package demo1;

import java.util.Comparator;
//创建一个NameComparator类,实现Comparator接口
public class NameComparator implements Comparator<Student> {
    @Override
    //实现接口中的抽象方法,用于进行名字之间的比较!
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}

o1.name之所以可以引用compareTo方法是因为String类中重写了compareTo方法:
在这里插入图片描述

//在另一个java文件中
package demo1;

import java.util.Comparator;
//实现Comparator接口
public class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {

        return o1.age - o2.age;
    }
}
package demo1;


import java.util.Arrays;
import java.util.Comparator;

//接口的应用!
// 比较两个对象的尝试!
// 实现关于comparable接口!
class Student implements Comparable<Student> {
    String name;
    int age;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    public int compareTo(Student o) {
        //比较年龄:

        if(this.age == o.age){
            return 0;
        }else if(this.age>o.age){
            return 1;
        }else {
            return -1;
        }
    }
        //比较姓名
      //  return this.name.compareTo(o.name);
    }
    public class Test {
  
      public static void main(String[] args) {
            Student[] arr1 = new Student[3];
            arr1[0] = new Student(10, "王五");
            arr1[1] = new Student(8, "李四");
            arr1[2] = new Student(9, "张三");
       
       System.out.println("排序前:" + Arrays.toString(arr1));
            //创建一个NameComparator对象。
    NameComparator nameComparator   =  new NameComparator();
            //进行名字间的比较!
            //Arrays.sort方法可以接收第二个参数!
            Arrays.sort(arr1,nameComparator);
       
           
     System.out.println("排序后:" + Arrays.toString(arr1));
           
        }
    }

这是按照姓名排序的结果:
在这里插入图片描述

按照年龄排序,则调用AgeComparator类:

     System.out.println("排序前:" + Arrays.toString(arr1));
     AgeComparator ageComparator = new AgeComparator();
            //根据年龄进行比较!
            Arrays.sort(arr1,ageComparator);
         System.out.println("排序后:"+Arrays.toString(arr1));

排序后,年龄从小到大!
在这里插入图片描述

我们通过创建不同的实现Comparator的类,并实现抽象方法compare,
当需要比较某一属性时,即调用某一属性对应类进行比较,这就是比较器的思想与实现!

二 深拷贝与浅拷贝

2.1 浅拷贝:

 所谓拷贝即将一个对象复制一份,由另一个引用指向新复制出的对象。

Cloneable接口:

要进行拷贝的类,需要先实现Cloneable接口.
在这里插入图片描述

Cloneable接口是一个空接口,代表着实现此接口的类可以被拷贝!

clone方法:

clone方法是Object类中用来拷贝对象的方法。
在这里插入图片描述

此方法被Native修饰,说明它是由C/C++等其他编程语言实现,不能查看其具体实现。

实现拷贝:

package demo1;

public class Person implements Cloneable{   //实现空接口的类,代表可以拷贝
              String name;
              int age ;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package demo1;
// 浅拷贝

public class Test {
    public static void main(String[] args) {
      Person person1 = new Person("张三",10);
      Person person2 =  person1.clone();
    }
}

(1)此时编译器报警告:
在这里插入图片描述

尽管clone方法的访问权限是protected且Test也是Object的子类,但是当person1调用clone方法时,
是在Person类的外部,所以报错。

解决这个问题,我们需要在子类中重写clone方法:

 protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

(2) 此时编译器又报警告:

在这里插入图片描述
这是异常的问题,以后会阐述到,解决这个问题,在main方法后,加上一条语句即可:

在这里插入图片描述
(3)编译器又报警告的原因是:
方法的返回值类型为Object类型,我们需要将其强制为Person类型。

package demo1;
// 浅拷贝

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
      Person person1 = new Person("张三",10);
      Person person2 = (Person) person1.clone();
        System.out.println(person1);
        System.out.println(person2);

    }
}

在这里插入图片描述

此刻,内存中情况如下:
在这里插入图片描述

浅拷贝:

拷贝的情况讲完了,那什么是浅拷贝呢?
当对象中有对象的创建时,此时只拷贝外部的对象,而不拷贝内部的对象,称为浅拷贝!
举例:

package demo1;
//创建一个Person类,实现接口
public class Person implements Cloneable{   //实现空接口的类,代表可以拷贝
              String name;
              int age ;

              Money money1 = new Money(10);

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
//重写克隆方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

package demo1;
//创建一个Money类
public class Money {
    int moneycount ;

    public Money(int moneycount) {
        this.moneycount = moneycount;
    }
}

package demo1;
// 浅拷贝

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
      Person person1 = new Person("张三",10);
      Person person2 = (Person) person1.clone();
        System.out.println("修改前:"+person1.money1.moneycount);
        System.out.println("修改前:"+person2.money1.moneycount);
//仅仅修改person2中的money对象的值,会不会改变person1中的值?
        person2.money1.moneycount = 20;
        System.out.println("修改后:"+person1.money1.moneycount);
        System.out.println("修改后:"+person2.money1.moneycount);

    }
}

在这里插入图片描述

在内存中情况:
在这里插入图片描述

这种未将对象 中的对象 拷贝的不彻底拷贝,我们称为浅拷贝!

2.2 深拷贝:

深拷贝也就是将对象中的对象也进行拷贝, 
这需要对Person类中的clone方法进行重写:
并且对Money类按照Person类中的格式进行重写编写

代码:

//Person类
package demo1;

public class Person implements Cloneable{   //实现空接口的类,代表可以拷贝
              String name;
              int age ;

              Money money1 = new Money(10);

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    //重写后的方法
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person) super.clone();    //谁调用了super方法,不需要this指定对象。
        //对于对象中的对象也进行拷贝!
        tmp.money1 = (Money) this.money1.clone();
        return tmp;



    }
}

//Money类
package demo1;

public class Money implements Cloneable {
    int moneycount ;

    public Money(int moneycount) {
        this.moneycount = moneycount;
    }
//也重写clone方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
//测试类
package demo1;
// 浅拷贝

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
      Person person1 = new Person("张三",10);
      Person person2 = (Person) person1.clone();
        System.out.println("修改前:"+person1.money1.moneycount);
        System.out.println("修改前:"+person2.money1.moneycount);

        person2.money1.moneycount = 20;
        System.out.println("修改后:"+person1.money1.moneycount);
        System.out.println("修改后:"+person2.money1.moneycount);

    }

在这里插入图片描述
结果表明,此时深拷贝成功,修改person2中的money值,不会改变person1中的值!

在内存中的展示:
在这里插入图片描述

  • 36
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值