Java抽象类和接口(2)

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


一、排序

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所指向的对象拷贝一份给person2System.out.println("修改前:"+ person1.m.money); //12.5System.out.println("修改前:"+ person2.m.money); //12.5person2.m.money = 99.9;System.out.println("修改后:"+ person1.m.money); //99.9System.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所指向的对象拷贝一份给person2System.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.mzph.cn/news/173945.shtml

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

相关文章

BetaFlight模块设计之三十七:SBUS

BetaFlight模块设计之三十七&#xff1a;SBUS 1. 源由2. sbus启动&动态任务3. 主要函数3.1 sbus初始化3.2 sbusFrameStatus更新3.3 rxFrameTimeUs3.4 sbusDataReceive接收数据 4. 辅助函数4.1 sbusChannelsDecode 5. 参考资料 1. 源由 接着BetaFlight模块设计之三十六&…

Leetcode—266.回文排列【简单】Plus

2023每日刷题&#xff08;四十&#xff09; Leetcode—266.回文排列 C语言实现代码 char chara[26] {0};int calculate(char *arr) {int nums 0;for(int i 0; i < 26; i) {nums arr[i];}return nums; }bool canPermutePalindrome(char* s) {int len strlen(s);for(in…

零基础在ubuntu上搭建rtmp服务器-srs

搭建服务器 搭建 SRS&#xff08;Simple-RTMP-Server&#xff09;服务器需要一些步骤&#xff0c;以下是一个简单的步骤指南。请注意&#xff0c;SRS 的配置可能会有所不同&#xff0c;具体取决于你的需求和环境。在开始之前&#xff0c;请确保你的 Ubuntu 系统已经连接到互联…

高效记账,轻松管理,批量记账与柱形图分析助你掌控收支明细

你是否曾经因为繁琐的记账过程而感到烦恼&#xff1f;是否曾经因为无法全面掌握个人或企业的收支情况而感到困惑&#xff1f;现在&#xff0c;我们为你带来了一种全新的高效记账方式&#xff0c;让你从此告别繁琐&#xff0c;轻松掌控收支明细。 首先第一步我们要打开晨曦记账…

商城免费搭建之java商城 鸿鹄云商 B2B2C产品概述

【B2B2C平台】&#xff0c;以传统电商行业为基石&#xff0c;鸿鹄云商支持“商家入驻平台自营”多运营模式&#xff0c;积极打造“全新市场&#xff0c;全新 模式”企业级B2B2C电商平台&#xff0c;致力干助力各行/互联网创业腾飞并获取更多的收益。从消费者出发&#xff0c;助…

pytest系列——pytest-xdist插件之多进程运行测试用例|| pytest-parallel插件之多线程运行测试用例

pytest之多进程运行测试用例(pytest-xdist) 前言 平常我们功能测试用例非常多时&#xff0c;比如有1千条用例&#xff0c;假设每个用例执行需要1分钟&#xff0c;如果单个测试人员执行需要1000分钟才能跑完当项目非常紧急时&#xff0c;会需要协调多个测试资源来把任务分成两…

警惕!AI正在“吞食”你的数据

视觉中国供图 □ 科普时报记者 陈 杰 AI大模型的热度&#xff0c;已然开始从产业向日常生活渗透&#xff0c;并引起不小的舆论旋涡。近日&#xff0c;网友指出国内某智能办软件有拿用户数据“投喂”AI之嫌&#xff0c;引发口水的同时&#xff0c;再度把公众对AI的关注转移到数…

使用paddledetection的记录

首先在这里使用的是是paddle--detection2.7的版本。 成功进行训练 目录&#xff1a; 目录 数据集准备 配置文件的修改 使用的是BML的平台工具&#xff1a; !python -m pip install paddlepaddle-gpu2.5 -i https://mirror.baidu.com/pypi/simple --user %cd /home/aistudio…

Rust语言入门教程(七) - 所有权系统

所有权系统是Rust敢于声称自己为一门内存安全语言的底气来源&#xff0c;也是让Rust成为一门与众不同的语言的所在之处。也正是因为这个特别的所有权系统&#xff0c;才使得编译器能够提前暴露代码中的错误&#xff0c;并给出我们必要且精准的错误提示。 所有权系统的三个规则…

Anaconda安装教程(超详细版)

目录 一、Anaconda简介 二、运行环境 三、安装Anaconda 四、手动配置环境变量&#xff08;重点&#xff09; 五、测试Anaconda环境是否配置成功 一、Anaconda简介 Anaconda&#xff0c;一个开源的Python发行版本&#xff0c;可用于管理Python及其相关包&#xff0c;包含了…

慕尼黑电子展采访全程 | Samtec管理层对话电子发烧友:虎家卓越服务

【摘要/前言】 今年的慕尼黑上海电子展上&#xff0c;Samtec大放异彩&#xff0c;特装展台一亮相就获得了大家的广泛关注&#xff0c;展台观众络绎不绝。 作为深耕连接器行业数十年的知名厂商以及Electronica的常客&#xff0c;Samtec毫无疑问地获得了大量媒体朋友的关注和报…

【数据结构】二叉树之链式结构

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 一、前置说明二、二叉树的遍历2.1 前序遍历2.2 中序遍历2.3 后序遍历2.4 层序遍历 三、…

如何在本地安装部署WinSCP,并实现公网远程本地服务器

可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器 文章目录 可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器1. 简介2. 软件下载安装&#xff1a;3. SSH链接服务器4. WinSCP使用公网TCP地址链接本地服务器5. WinSCP使用固定公网TCP地址访问服务器 1. 简介 …

送PDF书 | 豆瓣9.2分,超250万Python新手的选择!蟒蛇书入门到实践

在此疾速成长的科技元年&#xff0c;编程就像是许多人通往无限可能世界的门票。而在编程语言的明星阵容中&#xff0c;Python就像是那位独领风 骚的超级巨星&#xff0c; 以其简洁易懂的语法和强大的功能&#xff0c;脱颖而出&#xff0c;成为全球最炙手可热的编程语言之一。 …

Gitea和Jenkins安装

Gitea Gitea&#xff1a;https://dl.gitea.com/gitea/1.21.0/ Jenkins&#xff1a;https://www.jenkins.io/download/ 数据库配置 可以参考官方文档-https://docs.gitea.cn/1.20/installation/database-prep&#xff0c;这里以MySQL作为讲解 MySQL 在数据库实例上&#xf…

智能物流时代:快递物流信息订阅与推送API自动推送物流变更信息

引言 在当今数字化和智能化的时代&#xff0c;物流行业也在迅速演变&#xff0c;通过技术创新提高效率、提升服务质量。其中&#xff0c;快递物流信息订阅与推送API的自动推送功能成为推动物流领域发展的重要驱动力。本文将深入探讨这一趋势&#xff0c;并分析快递物流信息订阅…

完美解决:vue.js:6 TypeError: Cannot read properties of undefined (reading ‘0‘)

Vue项目出现以下报错&#xff1a; 原因&#xff1a; 在渲染的时候&#xff0c;不满足某个条件而报错&#xff0c;或者某个属性丢失或后台没传过来导致 我这里出现的原因是后台给我传递过来的数组中&#xff0c;其中有一条少传了一个我在渲染时需要用的属性&#xff0c;没让后台…

如何使用Java支付宝沙箱环境并公网调用sdk创建支付单服

Java支付宝沙箱环境支付&#xff0c;SDK接口远程调试【内网穿透】 1.测试环境 MavenSpring bootJdk 1.8 2.本地配置 获取支付宝支付Java SDK,maven项目可以选择maven版本,普通java项目可以在GitHub下载,这里以maven为例 SDK下载地址&#xff1a;https://doc.open.alipay.com…

阻塞队列及简单实现,生产者消费者模型

文章目录 阻塞队列阻塞队列是什么生产者消费者模型阻塞队列的实现 阻塞队列 阻塞队列是什么 阻塞队列是一种特殊的队列. 也遵守 “先进先出” 的原则. 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素当队列空的时候, 继续出队列也会阻塞, 直到有其他线…

有效实施的五条教学策略

作为老师&#xff0c;是否曾为如何提高教学质量而苦恼&#xff1f;也为如何引导学生而思考&#xff1f;如果你正面临这些困扰&#xff0c;那么这篇文章将对你有帮助。为你介绍五条教学策略&#xff0c;帮你实施教学&#xff0c;提高效果。 明确教学目标 你是否知道你的教学目标…