Java抽象类和接口(2)

news2024/11/22 5:46:41

 🐵本篇文章继续对接口相关知识进行讲解


一、排序

1.1 给一个对象数组排序:

class Student {
    public String name;
    public int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String toString() {
        return "name:"+name+" age:"+age;
    }
}

public class Test {

    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("Sans", 18);
        students[1] = new Student("Frisk", 8);
        students[2] = new Student("Chara", 9);

        Arrays.sort(students); //给数组排序
        System.out.println(Arrays.toString(students)); //将排序后数组排序后转化为字符串打印

        //Arrays类中有一个toString静态方法,但这个方法并不是重写的Object类的方法,
        //在这个方法中,间接调用了Object中的toString方法
    }
}

可以发现,这样写编译会报错,原因就是Student类中有name和age两种属性,但在进行排序时编译器并不知道按什么排序,错误信息显示如下:

在ComparableTimSort.java文件的320行代码中有这样一条语句:

311    private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
314        assert lo < hi;
315        int runHi = lo + 1;
316        if (runHi == hi)
317            return 1;
318
319        // Find end of run, and reverse range if descending
320       if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending
...        ...

在311行代码的形参有一个Object[]a,这个参数其实接收的就是我们要排序的数组(这个方法是由Arrays.sort间接调用的)在320行代码可以看到数组被强制类型转换为了Comparable这个接口,我们的数组是Student类,Student类并没有实现Comparable这个接口,所以不能进行强转,那么现在就要实现这个接口,实现一个接口就必须重写其包含的抽象方法,在Comparable接口中有下面方法:

public interface Comparable<T> {
    public int compareTo(T o);
}

也就是要在Student类中对compareTo方法根据我们的需求进行重写,如果根据学生的姓名进行比较:

class Student implements Comparable<Student>{

.......

public int compareTo(Student student) {
    return this.name.compareTo(student.name);
}

<>中用来写要比较的对象所属的类,在compareTo方法中也调用了compareTo方法,这里是调用的String类中的方法,因为this.name是String类型,在String类中也重写了compareTo方法,它的作用就是用来比较字符串

现在完整代码显示如下:

import java.util.Arrays;

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

    public int compareTo(Student student) {
        return this.name.compareTo(student.name);
    }
}

public class Test {

    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("Sans", 18);
        students[1] = new Student("Frisk", 8);
        students[2] = new Student("Chara", 9);

        Arrays.sort(students); //给数组排序
        System.out.println(Arrays.toString(students)); //将排序后数组排序后转化为字符串打印

        //Arrays类中有一个toString静态方法,但这个方法并不是重写的Object类的方法,
        //在这个方法中,间接调用了Object中的toString方法
    }
}

简单来说compareTo就是我们给编译器提供的比较方法,使其按照这个进行排序

也可以自己模拟一个排序方法(冒泡排序思想):

public static void mySort(Comparable[] comparables) { //任何实现Comparable接口的类都可以通过这个方法排序,类似于向上转型
    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) { //这一条语句发生了动态绑定,调用的是Student类中的compareTo方法
                //交换
                Comparable tmp = comparables[j];
                comparables[j] = comparables[j+1];
                comparables[j+1] = tmp;
            }
        }
    }
}

1.2 Comparator接口

Comparator接口中的compare方法也可以用来比较两个对象

public interface Comparator<T> {
    int compare(T o1, T o2);
}

举一个例子

import java.util.Comparator;
class Student {
public String name;

    public Student(String name) {
        this.name = name;
    }
}
class NameComparator implements Comparator<Student> {
    public int compare(Student student1, Student student2) {
        return student1.name.compareTo(student2.name);
        //前者>后者:返回大于0的数
        //前者<后者:返回小于0的数
        //前者=后者:返回0
    }
}

public class Test {
    public static void main(String[] args) {
        Student student = new Student("Sans");
        Student student1 = new Student("Frisk");

        NameComparator nameComparator = new NameComparator();
        System.out.println(nameComparator.compare(student, student1)); //13
    }
}

二、Cloneable接口

clone()方法是Object类中的一个成员方法,下面举一个克隆对象的实例:

class Person implements Cloneable{
    public String name;
    public Person(String name) {
        this.name = name;
    }

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

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("Sans");
        Person person2 = (Person) person1.clonePerson()
        System.out.println(person2.name);
    }
}

1. Person类实现Cloneable接口才能对这个类的对象进行克隆

2. person1调用clone()方法,并强转为Person赋给perosn2

3. 由于Object类是父类,所以应该用super来调用clone()方法

4. main方法为静态方法,所以必须在Person类中再写一个方法来使用super来调用clone()方法

5. throws CloneNotSupportedException暂且不管,先模仿

2.1 浅拷贝

浅拷贝是指创建一个新对象,并将原始对象的值拷贝到新对象中,但是这里原始对象中引用类型的成员的值也拷贝到了新对象中,这也就说明,原始对象和新对象中的原始引用和新引用都指向了同一个对象

class Money {
    public double money = 12.5;
}

class Person implements Cloneable{ //必须实现Cloneable这个接口才能克隆这个Person类
    public String name;
    public Money m;

    public Person(String name) {
        this.name = name;
    }
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1 = new Person("Sans");
        Person person2 = (Person) person1.clone(); //将person1所指向的对象拷贝一份给person2

        System.out.println("修改前:"+ person1.m.money); //12.5
        System.out.println("修改前:"+ person2.m.money); //12.5
        person2.m.money = 99.9;
        System.out.println("修改后:"+ person1.m.money); //99.9
        System.out.println("修改后:"+ person2.m.money); //99.9
    }
}

上述代码执行完perosn2.m.money = 99.9后person1.m.money和person2.m.money都变成了99.9

2.2 深拷贝

深拷贝就是在浅拷贝的基础上,新对象的引用字段所指向的对象也是原始对象的被拷贝引用字段所指向对象的拷贝,可以简单理解为将一个对象完全拷贝了一份

class Money implements Cloneable{
    public double money = 12.5;
    public Object cloneMoney() throws CloneNotSupportedException {
        return super.clone(); //由于要拷贝一份m所指对象,所以Money类也要写一个方法并使用super调用clone()方法
    }
}

class Person implements Cloneable{ //必须实现Cloneable这个接口才能克隆这个Person类
    public String name;

    public Money m;

    public Person(String name) {
        this.name = name;
        m = new Money();
    }
    public Object clonePerson() throws CloneNotSupportedException {
        Person tmp = (Person)super.clone(); //拷贝一份person1所指对象
        tmp.m = (Money) this.m.cloneMoney(); //拷贝一份m所指对象并赋值给新对象的m引用
        return tmp; 
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1 = new Person("Sans");
        Person person2 = (Person) person1.clonePerson(); //将person1所指向的对象拷贝一份给person2

        System.out.println("修改前:"+ person1.m.money);
        System.out.println("修改前:"+ person2.m.money);
        person2.m.money = 99.9;
        System.out.println("修改后:"+ person1.m.money);
        System.out.println("修改后:"+ person2.m.money);


    }
}

深拷贝后,执行完person2.m.money,person1.m.money的值就不会改变

三、内部类

内部类定义在类中,相当于在类中嵌套了一个类

3.1 静态内部类

静态内部类由static修饰的一个类,如下:

public class Test {
    private static int a;
    public int b;

    static class Inner {
        public int c;

        public void test() {
            Test test = new Test();
            System.out.println(a); //内部类只能访问外部类的静态成员
            System.out.println(test.b); //访问其它成员必须实例化外部类的对象
                                    //并用外部类对象的引用来访问非静态成员
            System.out.println(c);
        }
    }
    public static void main(String[] args) {
        Test.Inner inner = new Test.Inner(); //实例化静态内部类对象
        inner.test(); //用内部类对象的引用访问内部类的test方法
    }
}

3.2 匿名内部类

public class Test {
    public void func() {
        System.out.println("test()");
    }

    public static void main(String[] args) {
        new Test().func(); //匿名对象
        new Test().func(); //如果有对象只使用一次,则使用匿名对象
        //这里创建了两个对象
    }
}

接下来看匿名内部类:

interface InterFace {
    void func();
}

class A implements InterFace{

    public void func() {
        System.out.println("A");
    }

}

public class Test {
    public static void main(String[] args) {
        InterFace a = new InterFace() {
            public void func() {
                System.out.println("B");
            }
        };

        a.func(); //打印结果为B
}

下图红框部分即为匿名内部类


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

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

相关文章

【Axure高保真原型】3D金字塔图_移入显示数据标签

今天和大家分享3D金字塔图_移入显示数据标签的原型模板&#xff0c;鼠标金字塔区域时&#xff0c;对应区域会变绿&#xff0c;可以查看该区域对应的项目和数据&#xff0c;这个原型模板是用Axure原生元件制作的&#xff0c;所以无需联网&#xff0c;而且可以自由修改样式、交互…

Allegro层叠中的介电常数如何填写指导说明

Allegro层叠中的介电常数如何填写指导说明 在用Allegro进行PCB设计的时候,需要在cross-section中设置好每个层的信息,包括层命名,每层的厚度等等信息。如下图 一般来说,这些信息就足够了 但是对于有仿真需求或者等长设计需要使用ps作为延时单位的设计的时候,需要额外在层…

postman自动化接口测试

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

Java基础小结

Java 基础小结 Java 基础概念与常识 什么是 Java ? Java 是 1995 年由 sun 公司推出的一门高级语言。 Java 的四个基本特性是面向对象、平台无关性、安全性和简单性。 具体特点如下: 简单易学。 平台无关性。 面向对象 面向对象是一种程序设计技术&#xff0c;以木匠工…

Docker配置Halo搭建个人博客-快速入门

Docker配置Halo搭建个人博客-快速入门 1 官方文档2 安装Halo2.1 创建Halo主目录2.2 远程下载配置文件2.3 编辑配置文件2.4 拉取最新镜像2.6 查看容器2.7 开放服务器的防火墙 3 运行3.1 运行项目3.2 停止项目 4 常见问题4.1 没有权限4.2 ommand netstart not found, did you mea…

体育网站的技术 SEO:完整指南

您熟悉体育网站管理行业的快节奏、不断变化的性质。您的网站提供最新的体育新闻和信息&#xff0c;包括实时比分更新。但是&#xff0c;如果人们不容易找到它&#xff0c;那么你所有的精彩内容都是徒劳的。这就是体育网站技术 SEO 综合指南的用武之地&#xff01; 本指南将教您…

【axios】拦截器:axios.interceptors.request.use|axios.interceptors.response.use

文章目录 概述设置拦截器Axios 拦截器的实现任务注册任务编排任务调度 来源 概述 axios有请求拦截器&#xff08;request&#xff09;、响应拦截器&#xff08;response&#xff09;、axios自定义回调处理&#xff08;这里就是我们常用的地方&#xff0c;会将成功和失败的回调…

论文阅读——DINOv

首先是关于给了提示然后做分割的一些方法的总结&#xff1a; 左边一列是prompt类型&#xff0c;右边一列是使用各个类型的prompt的模型。这些模型有分为两大类&#xff1a;Generic和Refer&#xff0c;通用分割和参考分割。Generic seg 是分割和提示语义概念一样的所有的物体&am…

开源四轴协作机械臂ultraArm激光雕刻技术案例!

注意安全事项 开始之前&#xff0c;请确保您已采取适当的安全措施&#xff0c;例如用于激光操作的防护眼镜、灭火器和通风良好的区域。 引言 随着科技的不断进步&#xff0c;激光雕刻技术已经成为当今制造行业中不可或缺的一部分。它以其高精度、高效率和广泛的材料适应性&…

Docker可视化工具Portainer(轻量)或者Docker容器监控之 CAdvisor+InfluxDB+Granfana(重量)

Docker轻量级可视化工具Portainer 是什么 Portainer 是一款轻量级的应用&#xff0c;它提供了图形化界面&#xff0c;用于方便地管理Docker环境&#xff0c;包括单机环境和集群环境。 安装 官网 https://www.portainer.io/ https://docs.portainer.io/v/ce-2.9/start/instal…

springboot+vue实现websocket通信实例,进入页面建立连接

springbootvue实现websocket通信实例 进入页面建立连接 前端代码&#xff1a; <template><div class"app-container"><el-form :model"queryParams" ref"queryForm" size"small" :inline"true" v-show&qu…

uniapp基础-教程之HBuilderX基础常识篇03

该内容为了大家更好的理解&#xff0c;将每个页面进行分离&#xff0c;单独创建项目&#xff0c;如在index中之写只写了一个搜索框&#xff0c;将其他页面分别放在HBuilderX目录中的components中&#xff0c;没有的可自行创建。 然后在components中创建轮播图新建一个swiper.v…

行情分析——加密货币市场大盘走势(11.27)

大饼周末震荡了两天&#xff0c;目前价格又回到了37300附近&#xff0c;最近多头多次上攻也不能涨出新高&#xff0c;那么就继续等待下跌即可。 空单策略&#xff1a;入场37300 加仓38000 止盈34000-33000 止损39000 以太现在在蓝色上涨趋势线上面&#xff0c;目前笔者一直持有…

5. 链表

内存空间是所有程序的公共资源&#xff0c;在一个复杂的系统运行环境下&#xff0c;空闲的内存空间可能散落在内存各处。我们知道&#xff0c;存储数组的内存空间必须是连续的&#xff0c;而当数组非常大时&#xff0c;内存可能无法提供如此大的连续空间。此时链表的灵活性优势…

k8s-deployment控制器 5

K8s控制器是Kubernetes&#xff08;简称k8s&#xff09;系统中一个重要的组成部分&#xff0c;它是一个管理Pod的中间层&#xff0c;可以创建和管理多个Pod副本&#xff0c;确保它们按照预定的数量和行为进行运行。 通过编写yaml文件将信息全部存到etcd中&#xff0c;控制器通…

红黑树底层原理

文章目录 什么是红黑树红黑树的性质插入叔叔存在且为红叔叔存在且为黑或叔叔不存在 调整总结右旋左旋旋转总结 什么是红黑树 红黑树也是一种二叉搜索树&#xff0c;只不过给这棵树上的节点带上了颜色&#xff0c;但是已经有了AVL树为什么还要搞出红黑树这个东西呢&#xff1f;…

【高效开发工具系列】MapStruct入门使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Node.js+Express+Nodemon+Socket.IO构建Web实时通信

陈拓 2023/11/23-2023/11/27 1. 简介 Websocket WebSocket是一种在单个TCP连接上提供全双工通讯的协议。特别适合需要持续数据交换的服务&#xff0c;例如在线游戏、实时交易系统等。 Websocket与Ajax之间的区别 Ajax代表异步JavaScript和XML。它被用作一组Web开发技术&…

Linux——使用命令查看文件和文件夹数量

目录 一、相关命令参数解析二、查看当前目录下的文件数量2.1 包含子目录中的文件2.2 不包含子目录中的目录 三、查看当前目录下的文件夹个数3.1 不包含目录中的目录3.2 包含目录中的目录 四、查看当前文件夹下叫某某的文件的数量实例 五、总结 一、相关命令参数解析 "&qu…

山西电力市场日前价格预测【2023-11-27】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-11-27&#xff09;山西电力市场全天平均日前电价为40.02元/MWh。其中&#xff0c;最高日前电价为293.07元/MWh&#xff0c;预计出现在17:45。最低日前电价为0.00元/MWh&#xff0c;预计出现…