零基础Java第十六期:抽象类接口(二)

news2024/11/14 5:54:03

目录

一、接口(补)

1.1. 数组对象排序

1.2. 克隆接口

1.3. 浅拷贝和深拷贝 

 1.4. 抽象类和接口的区别


一、接口(补)

1.1. 数组对象排序

     我们在讲一维数组的时候,使用到冒泡排序来对数组里的元素进行从小到大或从大到小的排序。上一期里面我们通过Comparable接口来比较Student对象里面的成员变量,如果Student对象实例化一个数组,并且数组里面有多个元素,我们也是可以通过冒泡排序来实现。 

//定义Student类

public class Student implements Comparable<Student>{
    public int age;

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

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

    @Override
    public int compareTo(Student o) {
        return o.age - this.age;
    }
}
import java.util.Arrays;
import java.util.Comparator;

public class Main {
    public static void BubbleSort(Comparable[] compare){
        for (int i = 0; i < compare.length-1; i++) {//表示比较的趟数
            for (int j = 0; j < compare.length-1-i; j++) {
                if(compare[j].compareTo(compare[j+1]) > 0){
                    Comparable temp = compare[j];
                    compare[j] = compare[j+1];
                    compare[j+1] = temp;
                }
            }
        }
    }

    public static void main(String[] args) {
        Student[] stu = new Student[3];
        stu[0] = new Student(10);
        stu[1] = new Student(8);
        stu[2] = new Student(11);

        BubbleSort(stu);
        System.out.println(Arrays.toString(stu));
    }
}

   以上代码可以参考博主之前的博客,这里就不做过多讲解了。以下为运行结果:

1.2. 克隆接口

public class Person {
    public String name;
    public int age;

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

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

public class Main {
    public static void main(String[] args) {
        Person one = new Person("Paul",17);
        Person two = one.clone();//报错:'clone()' has protected access in 'java.lang.Object'
    }
}

      我们如果想把one这个对象克隆到two这个对象,就可以使用clone这个方法,但是会报错,我们可以查看一下源码。双击shift,勾选“include non-project items”,在搜素框里面输入Object,点击Object java.lang,就可以看源码了。可以看到被protected关键字修饰Main类与clone方法不在同一个包路径下,所以在Main类里面无法通过Person类来访问。

package java.lang;

import jdk.internal.vm.annotation.IntrinsicCandidate;

@IntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;

       既然不能直接访问,那我们只能进行间接访问。此时我们还需要再重写一个方法,重写之后依然会报错。我们来看一下Object里面的源码,把“throws CloneNotSupportedException”复制粘贴到main方法后面,可以看到等号左边是子类Person,右面却是父类Object,此时就需要向下转型并强转来对父类进行赋值。

     但光有这些还是不够的,我们还差最后一步,实现克隆接口。Cloneable接口里面没有任何实现,所以就是一个空接口。

public class Person implements Cloneable

//Cloneable的源码
public interface Cloneable {
}

 以下是完整代码和运行结果:

public class Person implements Cloneable{
    public String name;
    public int age;

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

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person one = new Person("Paul",17);
        Person two = (Person) one.clone();
        System.out.println(two);
    }
}

       下面我们来画图讲一下克隆是如何在栈和堆上工作的: one对象先在栈上开辟一块内存空间,指向堆上的地址,调用clone方法之后,直接又在堆上创建出一块,而two对象也指向了新克隆的空间。

1.3. 浅拷贝和深拷贝 

(1)浅拷贝

       看下面一段代码,我们在上面的代码基础上新增了一个Money类,在Main,我们先访问并打印两个对象的成员变量Money,然后修改two对象中的money的值,然后再打印,可以看到我明明只修改了two对象的成员变量,但one对象也被修改了。

class Money{
    public double money = 93.5;
}

public class Person implements Cloneable{
    public String name;
    public int age;
    public Money m;

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

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

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

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person one = new Person("Paul",19);
        Person two = (Person) one.clone();

        System.out.println(one.m.money);
        System.out.println(two.m.money);
        System.out.println("===============");

        two.m.money = 86.4;
        System.out.println(one.m.money);
        System.out.println(two.m.money);
    }
}

       相信老铁们看到这个图之后,就一目了然了。虽然说one所指向的对象被拷贝克隆了一份,但m所指向的money对象却没有被克隆,one和two所指向的是同一个money对象,这就会导致我们修改了money对象的值,两个变量都会被修改。这就是浅拷贝。那么老铁们想一下如何实现深拷贝呢?

(2)深拷贝 

       我们给Money这个类后面也来上接口Cloneable,也需要对Money类里面进行方法重写,与上面的浅拷贝不同的是,我们对Person类里面的克隆重写进行了改动。

class Money implements Cloneable{
    public double money = 93.5;

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

public class Person implements Cloneable{
    public String name;
    public int age;
    public Money m;

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person)super.clone();
        tmp.m = (Money) this.m.clone();
        return tmp;
    }
}

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person one = new Person("Paul",19);
        Person two = (Person) one.clone();

        System.out.println(one.m.money);
        System.out.println(two.m.money);
        System.out.println("===============");

        two.m.money = 86.4;
        System.out.println(one.m.money);
        System.out.println(two.m.money);
    }
}

 1.4. 抽象类和接口的区别

        抽象类和接口都是 Java 中多态的常见使用方式,都需要重点掌握,同时又要认清两者的区别。

        核心区别: 抽象类中可以包含普通方法和普通字段,这样的普通方法和字段可以被子类直接使用(不必重写),而接口中 不能包含普通方法, 子类必须重写所有的抽象方法。

       再次提醒,抽象类存在的意义是为了让编译器更好的校验,像 Animal 这样的类我们并不会直接使用,而是使用它的子类. 万一不小心创建了 Animal 的实例, 编译器会及时提醒我们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2239962.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

django入门【05】模型介绍(二)——字段选项

文章目录 1、null 和 blank示例说明⭐ null 和 blank 结合使用的几种情况总结&#xff1a; 2、choices**choices 在 Django 中有以下几种形式&#xff1a;**&#xff08;1&#xff09; **简单的列表或元组形式**&#xff08;2&#xff09; **字典映射形式**&#xff08;3&#…

数据量大Excel卡顿严重?选对报表工具提高10倍效率

当几万行的数据把软件频频跑崩&#xff0c;当珍贵的数据资源无法便捷复用&#xff0c;当数据填报的本地文档在各个电脑中传来传去……在各大岗位要求中频频出现的Excel&#xff0c;作为个人办公软件绝无仅有&#xff0c;但作为企业场景下的报表工具&#xff0c;效率显然不足。 …

如何用WordPress和Shopify提升SEO表现?

选择合适的建站程序对于SEO优化非常重要。目前&#xff0c;WordPress和Shopify是两种备受推崇的建站平台&#xff0c;各有优势。 WordPress最大的优点是灵活性。它支持大量SEO插件&#xff0c;帮助你调整元标签、生成站点地图、优化内容结构等。这些功能让你能够轻松地提升网站…

vue 计算属性get set

<template><div id"app"><h1>用户信息</h1><p>全名&#xff1a;{{ fullName }}</p><input v-model"fullName" placeholder"请输入全名" /><p>姓&#xff1a;{{ firstName }}</p><p>…

PHP搭建开发环境(Windows系统)

要搭建一个完整的PHP动态网站&#xff0c;离不开操作系统、Web服务器、数据库、和PHP软件。 虽然有不错方便的方式&#xff0c;比如使用phpstudio等等等等许多面板都是非常快速不错的方式&#xff0c;但是这里是教会大家如何配置而不只是依赖别人整合好的面板软件&#xff0c;…

7.2 图像复原之空间滤波

图像复原&#xff08;只存在噪声的复原&#xff09;之空间滤波 文章目录 图像复原&#xff08;只存在噪声的复原&#xff09;之空间滤波前言1. 均值滤波器1.1 算术平均滤波器1.2 几何均值滤波器1.3 谐波平均滤波器1.4 反谐波平均滤波器 总结 前言 当一幅图像仅被加性噪声退化时…

化工防爆巡检机器人:在挑战中成长,为化工安全保驾护航

随着全球能源需求的不断攀升&#xff0c;化工行业的安全性与高效性愈发受到关注。化工设施规模巨大&#xff0c;而且其中多数存在高风险因素&#xff0c;像是易燃易爆化学物质、高温环境、有毒有害物质以及高压设备等。仅2023年&#xff0c;国内危化品事故就多达652起&#xff…

【数字图像处理+MATLAB】对图片进行伽马校正(Gamma Correction):使用幂律变换公式进行伽马变换

引言 伽马校正&#xff08;Gamma Correction&#xff09;是一种用于图像处理的技术&#xff0c;主要用于调整图像的亮度或对比度。其基本原理是对图像的每一个像素应用一个非线性变换&#xff0c;以更好地适应人眼的视觉感知。在数字图像处理中&#xff0c;伽马校正通常用于调…

scala 迭代更新

在Scala中&#xff0c;迭代器&#xff08;Iterator&#xff09;是一种用于遍历集合&#xff08;如数组、列表、集合等&#xff09;的元素而不暴露其底层表示的对象。迭代器提供了一种统一的方法来访问集合中的元素&#xff0c;而无需关心集合的具体实现。 在Scala中&#xff0c…

部署zabbix遇到问题: cannot find a valid baseurl for repo:centos-sclo-rh/x86 64 怎么解决 ?

安装 Zabbix 前端包&#xff0c;提示cannot find a valid baseurl for repo&#xff1a;centos-sclo-rh/x86 64 安装zabbix前端包 # yum install zabbix-web-mysql-scl zabbix-apache-conf-scl 解决办法&#xff1a; 原因是&#xff1a;CentOS7的SCL源在2024年6月30日停止维护…

SpringBoot(十九)创建多模块Springboot项目(完整版)

之前我有记录过一次SpringBoot多模块项目的搭建,但是那一次只是做了一个小小的测试。只是把各模块联通之后就结束了。 最近要增加业务开发,要将目前的单模块项目改成多模块项目,我就参照了一下我上次搭建的流程,发现总是有报错。上次搭建的比较顺利,很多细枝末节也没有仔细…

基于Python的智能无人超市管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

什么是量化交易

课程大纲 内容初级初识量化&#xff0c;理解量化 初识量化 传统量化和AI量化的区别 量化思想挖掘 量化思想的挖掘及积累技巧 量化代码基础&#xff1a; python、pandas、SQL基础语法 金融数据分析 常用金融分析方式 常用因子分析方式 数据分析实战练习 回测及交易引擎 交易引擎…

xcode-select: error: tool ‘xcodebuild‘ requires Xcode, but active developer

打开 .sh 文件所在的终端窗口&#xff0c;执行终端命令&#xff1a;sh 文件名.sh&#xff0c;出现如下错误&#xff1a; 解决办法&#xff1a;

PETR/PETRv2/StreamPETR论文阅读

1. PETR PETR网络结构如下&#xff0c;主要包括image-backbone&#xff0c;3D Coordinates Generator&#xff0c;3D Position Encoder&#xff0c;transformer Decoder四个模块。 把N 个视角的图像输入到骨干网络中以提取 2D 多视图特征。在 3D 坐标生成器中&#xff0c;首先…

除了 Postman,还有什么好用的 API 调试工具吗

尽管 Postman 拥有团队协作等实用特性&#xff0c;其免费版提供的功能相对有限&#xff0c;而付费版的定价可能对小团队或个人开发者而言显得偏高。此外&#xff0c;Postman 的访问速度有时较慢&#xff0c;这可能严重影响使用体验。 鉴于这些限制&#xff0c;Apifox 成为了一…

程序员做自媒体,你所不了解的提词器,原来还有这么多大用处

程序猿的出路&#xff0c;不只是外卖员&#xff01; 你或许以为提词器只是个“背词神器”&#xff1f;实际上&#xff0c;它的应用范围早已超出你的想象。从直播到会议&#xff0c;从视频拍摄到户外采访&#xff0c;每一种场景都有对应的提词神器&#xff0c;帮你提升效率、避…

DeBiFormer实战:使用DeBiFormer实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

JS 实现WebSocket通讯和什么是WebSocket

WebSocket 介绍&#xff1a; WebSocket 是一种网络传输协议&#xff0c;可在单个 TCP 连接上进行全双工通信。它允许服务器主动向客户端推送信息&#xff0c;客户端也能实时接收服务器的响应。 客户端 这里实现了将input内的内容发送给客户端&#xff0c;并将接收到的服务器的…

前端 JS面向对象 继承

目录 一、ES5通过prototype来继承 二、ES6 class实现 一、ES5通过prototype来继承 const Person{eyes:2,head:1}function Woman(){}Woman.prototypePersonconst ladynew Woman()console.log(lady)function Man(){}Man.prototypePersonconst mannew Man()console.log(man) 打…