关于接口中的一些常用实例以及比较方法的区别

文章目录

  • 文章导读
  • Object 类
    • toString() 获取对象信息
    • equals 对象比较方法
    • hashCode 获得对象的具体位置
  • 接口使用实例
    • Comparable 接口
    • Comparator 接口

文章导读

在本篇文章中,详解了什么是Object类,一些Object类中的方法,以及两种接口的实现从而达到对象的比较,文章中的所讲的Object类中的方法以及两种比较的接口都应该熟悉的掌握!!!

Object 类

object类是所有类的父类,在Java中是默认的,即使在定义类的时候没有显示的继承某个类,但是在Java中,每个类都会默认的继承Object类,所以,Object类的级别也就相当于所有类的祖宗!就像下面这种情况,实参在传对象时,形参的类型都可以定义成Object类型进行接受。

abstract class Experiment1{
    public abstract void action();
}
class Experiment2 extends Experiment1{
    public void action() {
        System.out.println("哈哈");
    }
}
public class Test {
    //定义形参为Object类型
    public static void method(Object obj) {
        //因为Object里没有action方法,所以转换成Experiment类型
        ((Experiment1)obj).action();
    }
    public static void main(String[] args) {
        Experiment2 experiment2 = new Experiment2();
        method(experiment2);
    }
}

关于接口中的一些常用实例以及比较方法的区别_第1张图片

可以看到并没有报错,所以证明了Object类就是所有类的父类,而在Object类中,又有许多可以经常用到的方法,下面我们看一下;按住Ctrl+点击Object

关于接口中的一些常用实例以及比较方法的区别_第2张图片

以上这些方法都是经常可以用到的,在这篇文章中会讲到getClass();equal();toString();clone();方法,请好好理解:

toString() 获取对象信息

toString()方法的作用是获取对象的信息,实例化一个对象后,使用toString()方法可以将字符串的信息在控制台打印出来,如下代码:

public class Test {
    private String name;
    private int age;

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

    public static void main(String[] args) {
        Test test =  new Test("李四",19);
        System.out.println(test);
    }
}

关于接口中的一些常用实例以及比较方法的区别_第3张图片

这是个什么东西,这并不是我实例化的对象内容啊,为什么会这样呢?下面看我解释:

首先我们先按住Ctrl+鼠标点击println这个方法,看看里面的是如何实现的。

关于接口中的一些常用实例以及比较方法的区别_第4张图片

关于接口中的一些常用实例以及比较方法的区别_第5张图片

关于接口中的一些常用实例以及比较方法的区别_第6张图片

所以刚刚最后打印出来的不是对象中的内容,那么要想打印出对象中的内容的话,需要在类中重写toString方法,因为:println方法最后是调用了Object类中的toString方法,所以才打印出了地址(这里可以理解成一个地址),因为所有的类都是Object类的子类,所以,通过动态绑定,利用在子类中重写父类的方法,最后调用子类中重写的方法,从而实现对象的打印:

关于接口中的一些常用实例以及比较方法的区别_第7张图片

equals 对象比较方法

public class Student {
    private String name;
    private int age;

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

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

    public static void main(String[] args) {
        //看起来一模一样对不对?
        Student student1 = new Student("李四",18);
        Student student2 = new Student("李四",18);
        //不能通过==进行判断
        //System.out.println(student1==student2);
        System.out.println(student1.equals(student2));
    }
}

关于接口中的一些常用实例以及比较方法的区别_第8张图片

这里不能通过==进行判断,因为两遍表达式都是基本类型的数据时,才能用 ==进行比较,而现在两边表达式都是引用类型的,所以不能比较,而这里换成equals进行比较的话也是false,这是为什么呢?那么,就要看一下这个equals的实现方式了,按住Ctrl+鼠标点击equals;

关于接口中的一些常用实例以及比较方法的区别_第9张图片

因为阿,在代码中,new了两次对象,虽然对象中的内容都是一样的,但他本质上是不一样的,它是在堆上开辟了两块空间,所以,在这里比较的是两块空间的地址,所以,得到的结果是false,如果要想对这两个对象进行比较,则要重写equals方法,下面重写:

    @Override
    public boolean equals(Object obj) {
        if(obj == null) {
            return false;
        }else if(this == obj) {
            return true;
        }else{
            //因为obj时object类型,里面没有name和age成员,所以要转换成Student
            return ((Student)obj).name.equals(((Student) obj).name) && ((Student) obj).age == ((Student) obj).age;
        }
    }

关于接口中的一些常用实例以及比较方法的区别_第10张图片

结论:如果要比较对象中的内容是否相同时,一定要重写equals方法

hashCode 获得对象的具体位置

现在回到刚刚调用的toString方法

在这里插入图片描述

在这里hashCode是计算出具体的对象位置,那么,请看下面代码:

  public static void main(String[] args) {
        //看起来一模一样对不对?
        Student student1 = new Student("李四", 18);
        Student student2 = new Student("李四", 18);
        System.out.println(student1.hashCode());
        System.out.println(student2.hashCode());
    }
}

关于接口中的一些常用实例以及比较方法的区别_第11张图片

算出了两串数字,这个数字是表示hashCode将地址以十六进制的形式打印出来,而这两个对象,因为内容是一样的,所以在逻辑上应该认为它们两个也应该存在一个地方,但是,本质上是不一样的,而如果想要在逻辑上把它们两个放在同一个地方,需要重写hashCode方法:

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

关于接口中的一些常用实例以及比较方法的区别_第12张图片

结论:hashCode方法时用来确定对象在内存中存储的位置是否相同

接口使用实例

Comparable 接口

Comparable比较两个对象的大小,如果对象之间要想比较谁大谁小,需要实现Comparable这个接口,然后重写里面的comparto方法,指定两个对象的比较方式。具体代码实现:

public class Student implements Comparable<Student> {
    private String name;
    private 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;
    }
     public static void main(String[] args) {
        Student student1 = new Student("李四", 18);
        Student student2 = new Student("王五", 20);
        System.out.println(student1.compareTo(student2));
    }
}

下面根据名字进行比较

 @Override
 //只需要重写里面的comparto方法即可
    public int compareTo(Student o) {
           return this.name.compareTo(o.name);
    }

可以看到重写的comparto方法,与前面的requals不同,conparto方法是比较两个对象的大小,只要在comparto的重写方法中指定根据对象中的什么内容进行比较,就可以比较出两个对象的大小。所以返回值是int,而equals是比较两个对象是否相等,返回值是bolean类型的;

而在这里还需要注意一点问题需要知道:

关于接口中的一些常用实例以及比较方法的区别_第13张图片

下面再举个例:对数组中的内容进行排序

关于接口中的一些常用实例以及比较方法的区别_第14张图片

如果在没有重写comparto方法的前提下只用正常的Arrays.sort方法对数组进行排序是会报错的,因为排序的是一个对象,需要实现Comparable接口,重写comparto方法,指定根据什么进行排序,年龄或者姓名,下面请看代码:

   //需要实现Comparable接口
public class Student implements Comparable<Student> {
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Test{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
           //根据名字进行排序
       @Override
    public int compareTo(Student o) {
        return this.name.compareTo(o.name);
    }
           //根据年龄进行排序
            //@Override
    //public int compareTo(Student o) {
       // return this.age-o.age;
   // }

   public static void main(String[] args) {
           Student[] arrays = new Student[]{new Student("zhangsan",14),new Student("lisi",11),new Student("wangwu",19)};
        Arrays.sort(arrays);
        System.out.println(Arrays.toString(arrays));
           }
}

关于接口中的一些常用实例以及比较方法的区别_第15张图片

Comparator 接口

Comparator接口也是实现两个对象进行比较,但是,这种比较方法比较独立,对类的侵入性不强,而上一种比较方法的缺点就是,当需要根据对象中不同的内容进行比较时,需要修改comparto方法中的内容,可能会对已经写好的代码造成影响,而这comparator这个接口则不会,下面通过代码讲解:

//根据年龄进行比较
class AgeCompar implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age-o2.age;
    }
}
//根据姓名进行比较
class NameCompar implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
public class Student{
    String name;
     int age;

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

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

    public static void main(String[] args) {
        Student student1 = new Student("李四", 18);
        Student student2 = new Student("王五", 20);
        //只需要实例化两个比较器的对象即可
        //通过引用调用比较器里面的方法实现内容的比较
        AgeCompar ageCompar = new AgeCompar();
        NameCompar nameCompar = new NameCompar();
        System.out.println(ageCompar.compare(student1, student2));
        System.out.println(nameCompar.compare(student1,student2));
    }

关于接口中的一些常用实例以及比较方法的区别_第16张图片

以上代码就是**比较器比较,**优点是所有的比较方法都可以共存,想根据什么比较只需要写一个比较器就可以了,不需要对已经写好的代码进行修改。

作一下总结:

1、如果==两边是引用数据类型,则需要注意;这比较的是两个引用是否指向同一个对象

2、如果两个对象要进行比较是否相等,则要调用equals方法并且重写equals方法,指定根据对象中的什么内容进行比较,

3、如果是两个字符串吹进行比较是否相等,则要调用equals方法,不用重写;

4、如果比较两个对象的大小,则要实现Comparable接口,重写里面的comparto方法,指定根据什么进行比较

5,如果是字符串比较大小,只需调用comparto方法即可

点是所有的比较方法都可以共存,想根据什么比较只需要写一个比较器就可以了,不需要对已经写好的代码进行修改。

你可能感兴趣的:(#,JavaSE语法,java,jvm,开发语言)