上篇(【Java基础篇 | 面向对象】—— 聊聊什么是接口(上篇))中我们已经对Java接口中有了一定的了解。本篇中我们将对Java接口进行更进一步的学习。加油吧!!!

一、接口使用实例

首先我们要使用记住一句话,对象与对象之间进行比较的话一定要实现对应的接口。只有我们实现了对应的接口之后才能证明这两个对象是可比较的

现在有一个整数数组,我们当然可以使用sort()方法来对这个整数数组进行升序或者降序排序。但是如果我们现在有一个学生类对象呢我们是无法直接拿两个学生类对象进行直接排序的。此时我们应该参照学生类中的某个属性来对这个学生类对象进行排序以达到我们想要的排序效果。

现在我们就以学生类中的年龄属性来进行排序吧:

我们在进行自定义类型的对象比较的时候,一定要实现可以比较的接口。比如如果我们的Student类实现Comparable接口, 并实现其中的compareTo方法。否则的话自定义类型的对象是无法进行比较的。

比较器(Comparator)

具体代码如下,请看:

import com.sun.javaws.IconUtil;
import java.util.Comparator;

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 ScoreComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1,Student o2) {
        return (int)(o1.score - o2.score);
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("jkl",1,87.3);
        Student student2 = new Student("ajk",2,87.3);

        // 依据年龄进行比较
        AgeComparator ageComparator = new AgeComparator();
        int ret = ageComparator.compare(student1,student2);
        System.out.println("ret = " + ret);

        // 依据成绩进行比较
        ScoreComparator scoreComparator = new ScoreComparator();
        int ret2 = scoreComparator.compare(student1,student2);
        System.out.println("ret = " + ret2);
    }
}

二、Clonable接口和深拷贝

浅拷贝

浅拷贝概念:浅拷贝是指在对一个对象进行拷贝时,只拷贝对象本身和其中的基本数据类型,而不拷贝对象内部的引用类型。因此,在浅拷贝的对象中,引用类型的变量指向的依旧是原始对象中的引用。

下面来进行举例。

深拷贝

深拷贝是指在对一个对象进行拷贝时,不仅拷贝对象本身和其中的基本数据类型,同时也拷贝对象内部的引用类型。因此,在深拷贝的对象中,引用类型的变量指向的是全新的对象。

好了,现在来总结一下:clone方法是Object类中的一个方法,调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法,必须要先实现Clonable接口, 否则就会抛出CloneNotSupportedException异常.

下面是深拷贝的代码举例:

class Money implements Cloneable {
    public double money;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Student implements Cloneable {
    public int age;
    public Money m = new Money();

    public Student(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //return super.clone();
        Student tmp = (Student)super.clone();
        tmp.m = (Money)this.m.clone();
        return tmp;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1 = new Student(21);
        student1.m.money = 52.0;
        Student student2 = (Student)student1.clone();
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);
        System.out.println("分割线--------------");
        student1.m.money = 18.8;
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);
    }
}

运行结果如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇)-LMLPHP
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇)-LMLPHP
好了,现在我们再来回顾一下什么是深拷贝:深拷贝就是在拷贝对象的同时创建一个新的对象,并将原对象中的所有数据逐个拷贝到新对象中去,包括成员变量引用的其他对象。这样可以确保原对象和拷贝对象之间的数据相互独立,互不影响。

三、Object类

在Java中,所有的类都直接或间接地继承自java.lang.Object类。Object类是Java类层次结构中的根类,它提供了一些通用的方法和功能,可以在所有类中使用。可以这么认为,Object类是所有类的父类。所以在Java中,即使我们不显式地在类声明中使用extends关键字继承Object类,所有的类仍然会隐式地继承Object类。这是因为Object类是Java类层次结构中的根类,所有的类都直接或间接继承自它。

对象比较equals()方法

hashcode()方法

最终代码如下,请看:

import java.util.Objects;

class Money implements Cloneable {
    public double money;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Money money1 = (Money) o;
        return Double.compare(money1.money, money) == 0;
    }

    @Override
    public int hashCode() {
        return Objects.hash(money);
    }
}
class Student implements Cloneable {
    public int age;
    public Money m = new Money();

    public Student(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //return super.clone();
        Student tmp = (Student)super.clone();
        tmp.m = (Money)this.m.clone();
        return tmp;
    }

    @Override
    public boolean equals(Object obj) {
        Student student = (Student)obj;
        return age == student.age;
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, m);
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student(19);
        Student student2 = new Student(19);
        System.out.println(student1.hashCode());
        System.out.println(student2.hashCode());
    }
}

小总结:

  • hashcode()方法用来确定对象在内存中存储的位置是否相同。
  • 实际上,hashcode()在散列表中才会用到(在散列表中hashcode()的作用就是获取对象的散列码,进而确定该对象在散列表中的位置);然而hashcode()在其它情况下没多大用。
  • 如果一个类没有重写hashCode()equals() 方法,那么它将使用从Object类继承而来的默认实现。如果默认实现的hashCode()equals()方法不符合我们的需求,此时我们就需要自己重写hashCode()equals()方法。
  • 定义一个自定义类型时,应该养成重写hashCode()equals()方法的习惯。

好了,本文到这里就结束了,再见啦友友们!!!
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇)-LMLPHP

12-10 02:35