【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇)

这篇具有很好参考价值的文章主要介绍了【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【JavaSE_primary】
本专栏旨在分享学习JavaSE的一点学习心得,欢迎大家在评论区交流讨论💌
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态

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

一、接口使用实例

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

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

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

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

如下图就是我们实现的Comparable接口中的compareTo方法。
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
如果我们要比较两个对象的引用的话(两个学生类对象按照年龄来进行排序),我们可以这样来写,请看:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
如果我们要比较的是一个学生类对象数组的话(按照年龄来进行比较),我们可以这样,请看:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
运行结果如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态

现在我们来试着使用自己写一个排序方法(冒泡排序)来对学生类对象进行排序。
请看下面我们自己实现的冒泡排序来对学生类对象按照年龄进行排序。代码如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
运行结果如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
现在我们来对上述冒泡排序中的代码进行解释:
排序的时候我们排序的是一个学生数组(按照年龄来进行排序),所以我们在进行排序的时候底层一定会去调用compareTo方法,所以冒泡排序中的参数一定为Comparable[] comparables,即接口数组。另外array数组(即学生类对象数组)中的每个元素都是一个学生类对象,而且每个学生类对象都实现了compareTo方法

比较器(Comparator)

好了,现在我们换一种排序的写法。上述学生类中有年龄也有分数,如果我们一会想依据年龄进行排序,一会又想用分数进行排序的话,如果按照compareTo()方法完成上述排序的话,那么根据我们比较依据的不同那么compareTo()方法中的内容也是不一样的(即我们需要修改compareTo方法中的内容)。
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
请看上图,上图中的compareTo()只能对学生类对象中的年龄进行排序而无法对学生类中的成绩进行排序,所以排序的内容就比较单一。此时我们就需要Comparator接口

好了,现在我们利用Comparator接口来实现学生类对象的排序工作,代码如下图,请看:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态

具体代码如下,请看:

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);
    }
}

运行结果如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
对比一下这两种接口(Comparator接口Comparable接口):经过上述的演示,我们不难发现Comparator接口更加的灵活。

二、Clonable接口和深拷贝

浅拷贝

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

下面来进行举例。

现在我们有一个Student学生类,如下图:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
同时新创建了一个学生类对象student1,该对象对应的内存结构图如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
现在我们想要把student引用所指向的对象克隆出来一份,如下图的克隆方式是错误的:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
要解决上述错误的话,我们需要修改三个地方。如下图【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
好了,现在重新运行一下程序,发现还是会报错,请看:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
我们需要实现一个接口以证明当前的类是可以进行克隆的。
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
运行结果如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态

浅拷贝的对象中,引用类型的变量指向的依旧是原始对象中的引用。请看举例:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
运行结果如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
解释:通过调用clone()方法,创建了student1的一个克隆对象student2。克隆的实现是通过调用Object类的clone()方法来完成的。
输出结果显示了两次student1.m.money和student2.m.money的值,分别为52.0。这是因为浅拷贝只是简单地复制字段的值,而对于引用类型的字段,只复制了引用地址,并没有复制该引用指向的实际对象。因此,student1和student2的m字段引用同一个Money对象。

【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态

深拷贝

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

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

三、Object类

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

对象比较equals()方法

【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
如上图:使用equals()方法来比较两个对象是否相等。
如果在Student类中没有重写equals()方法,则默认会使用Object类中的equals()方法,它执行的是比较对象引用的相等性(即比较两个对象在内存中的地址是否相同)。
因此,上图中的代码的最终结果就是False但是,如果我想要按照我们自己的方式来比较这两个对象是否相等的话我们就需要自己去重写equals()方法

现在,如果以两个对象的年龄是否相等为依据来判断两个对象是否相等的话,重写的equals()方法如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
如果我们相比较对象中的内容是否相等的话,我们需要根据自己的判断依据来重写Object类中的equals()方法

hashcode()方法

hashcode()方法用于返回对象的hash码,相当于对象的标识符,它可以将对象转换为整数以便更好的比较、存储对象。

好了,现在来举个栗子,假设当两个对象的年龄是一样的话,那么我们认为这两个对象存储的位置是相同的,请看代码:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
运行结果如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
如上图中的运行结果,虽然两个对象的年龄是不同的,但是这两个对象存储的位置确实相同的,这与我们判断两个对象是否相同的判断依据发生了冲突。
此时我们就需要自己重写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());
    }
}

运行结果如下:
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态
此时就说明这两个对象的位置是相同的。

小总结:

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

好了,本文到这里就结束了,再见啦友友们!!!
【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇),JavaSE,java,面向对象,多态文章来源地址https://www.toymoban.com/news/detail-752414.html

到了这里,关于【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【JavaSE】面向对象之多态

    通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。 必须要满足如下几个条件,缺一不可: 必须在 继承 体系下 子类必须要对父类中方法进行 重写 通过父类的引用调用重写的方法 定义测试类TestAnimal.java 编译器在编译代码时

    2024年02月11日
    浏览(36)
  • 【JavaSE】Java基础语法(十八):接口

    接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。 Java中接口存在的两个意义 用来定义规范 用来做功能的拓展 接口用interface修饰 类实现接口用implements表示 接口不能实例化 我们可以创建接口的实现类对象使用 接口的子类 要么重写接口中的所有抽

    2024年02月06日
    浏览(56)
  • 【JavaSE】面向对象编程思想之继承

     【本节目标】 1. 继承 2. 组合 目录 1. 为什么需要继承 2. 继承概念 3. 继承的语法 4. 父类成员访问 4.1 子类中访问父类的成员变量 4.2 子类中访问父类的成员方法 5. super 6. 子类构造方法 7. super和this 8. 再谈初始化 9. protected 10. 继承方式 11. final 12 继承与

    2024年02月12日
    浏览(41)
  • 【JAVASE】面向对象程序三大特性之一( 封装)

    ✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉n 🍎个人主页:再无B~U~G-CSDN博客 目标: 1.包的使用 2.static的使用 3. 代码块概念以及分类 面向对象程序三大特性:封装、继承、多态 。而类和对象阶段,主要研究的就是封装特性。何为

    2024年04月17日
    浏览(49)
  • 【javaSE】 面向对象程序三大特性之继承

    目录 为什么需要继承 继承的概念 继承的语法 注意事项  父类成员访问 子类中访问父类的成员变量 子类和父类不存在同名成员变量 子类和父类成员变量同名 访问原则 子类中访问父类的成员方法 成员方法名字不同 总结: 成员方法名字相同 总结: super 注意事项 子类

    2024年02月14日
    浏览(36)
  • Java面向对象之抽象类、类、接口分析参考

    Java 抽象类 抽象类不能实例化对象,所以抽象类必须被继承,才能被使用; Java 中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口 1. 抽象方法: 用Abstract 声明抽象方法,只包含一个方法名,没有方法体。方法名后面直接跟一

    2024年02月10日
    浏览(42)
  • 初始Java篇(JavaSE基础语法)(5)(类和对象(上))

    个人主页(找往期文章包括但不限于本期文章中不懂的知识点):我要学编程(ಥ_ಥ)-CSDN博客 目录 面向对象的初步认知 面向对象与面向过程的区别 类的定义和使用  类的定义格式 类的实例化 this引用 什么是this引用? this引用的特性 对象的构造及初始化 如何初始化对象(的

    2024年04月08日
    浏览(46)
  • 【JavaSE】面向对象编程思想之多态(图文详解)

    目录 1. 多态的概念 2. 多态实现条件 3. 重写 4. 向上转型和向下转型 4.1 向上转型 4.2 向下转型 5. 多态的优缺点 6. 避免在构造方法中调用重写的方法 多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。  总的来说

    2024年02月14日
    浏览(42)
  • 【JAVASE】带你了解面向对象三大特性之一(继承)

    ✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉 🍎个人主页:再无B~U~G-CSDN博客 Java 中使用类对现实世界中实体来进行描述,类经过实例化之后的产物对象,则可以用来表示现实中的实体,但是现实世界错综复杂,事物之间可能会存在一些关

    2024年04月09日
    浏览(52)
  • 【JAVASE】带你了解面向对象三大特性之一(多态)

    ✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉 🍎个人主页:再无B~U~G-CSDN博客 多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状 态。 总的来说:同一件事情,发生在不同对象

    2024年04月14日
    浏览(71)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包