图灵日记之java奇妙历险记--抽象类和接口
目录
- 抽象类
 - 概念
 - 抽象类语法
 
- 接口
 - 概念
 - 规则
 - 使用
 - 特性
 - 实现多个接口
 - 接口的继承
 - 接口使用实例
 - Clonable接口和深拷贝
 - 抽象类和接口的区别
 
- Object类
 
抽象类
概念
在面向对象的概念中,所有对象都是通过类来描述的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息描绘一个具体的对象,这样的类就是抽象类
- 使用abstract修饰的方法称为抽象方法
 - 使用abstract修饰的类称为抽象类
 - 抽象类是不可以进行实例化的
 - 抽象类当中可以和普通类一样定义成员变量和成员方法
 - 当一个普通的类继承了这个抽象类,那么需要重写这个抽象类当中的所有抽象方法
 - 抽象类的出现就是为了被继承
 - abstract和final不能共存
 - 被private static修饰抽象方法也不可以
 
抽象类语法
在java中,一个类如果被abstract修饰称为抽象类,抽象类中被abstract修饰的方法称为抽象方法,抽象方法不用给出具体的实现体
 注意:抽象类也是类,内部也可以包含普通方法和属性,甚至构造方法
接口
概念
接口是公共的行为规范标准,大家在实现时,只要符合规范标准
 就可以调用
 在java中,接口可以看成是:多个类的公共规范,是一种引用数据类型
规则
- 接口是使用interface方法修饰的
 - 接口当中不能有被实现的方法,意味着只能有抽象方法.但是两个方法除外:一个是static修饰的方法 一个是被default修饰的方法
 - 接口当作的抽象方法默认都是public abstract修饰的
什么都不写的时候默认abstract修饰 - 接口当中的成员变量默认都是public static final 修饰的
 - 接口不能进行实例化
 - 类和接口之间的关系,可以使用implements来进行关联
 - 接口也是有对应的字节码文件的
 
接口定义格式与定义类的格式基本相同,将class关键字换成interface关键字,就定义了一个接口
interface 接口名称 {}
 
使用
接口不能直接使用,必须要有一个"实现类"来实现该接口,实现接口中所有的抽象方法
class 类名称 implements 接口名称{// ...
}
 
注意:子类和父类之间是extends继承关系,类和接口之间是implements实现关系
特性
- 接口类型是一种引用类型,但是不能直接new接口的对象,无法实例化
 - 接口的每个方法都是public修饰的抽象方法,即接口中的方法被隐式的指定为public abstract(只能是public abstract, 其他修饰符都会报错)
 - 接口的方法是不能在接口实现的,只能由实现接口的类来实现
但在接口的方法里非要实现需要static或者default修饰
static修饰的方法不能重写
default修饰方法可重写可不重写 - 重写接口方法时,不能使用默认的访问权限
因为接口方法里默认就是public abstract,又因为子类的访问权限大于等于父类,子类只能被public修饰 - 接口中可以含有变量,但是接口中的变量会被隐式的指定为public static final 变量
 - 接口不能有代码块(实例代码块和静态代码块)和构造方法
 - 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是class
 - 如果类没有实现接口中的所有的抽象方法,则类必须被设置为抽象
 
实现多个接口
接口解决java多继承的问题
abstract class Animal{public String name;Animal(String name) {this.name = name;}abstract public void eat();abstract public void swim();
}
 
动物里并不是所有的动物都可以游泳,所以把swim写在Animal这个类里面不好,但是如果你把swim写到一个类就行了嘛?但是java不支持同时继承多个类,所以写进类里也不行,所以我们把他封装成了接口
注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类
 必须设置为抽象类
接口的继承
在java中,类和类之间是单继承的,一个类可以实现多个接口,接口和接口之间可以多继承.即用接口可以达到多继承的目的
interface walk {public void walk();
}
interface run extends walk {public void run();
}
 
run接口有walk接口的特性,可以使用extends关键字来实现复用的效果,extends理解为拓展的意思,即run拓展了walk的功能
 run接口不仅具备run接口本身的功能,而且具备walk这个接口的功能
interface A {public void a();
}
interface B extends A{public void a();
}
class test implements B{@Overridepublic void a() {}
}
 
接口B和接口A有一样的方法,当接口B拓展接口A时,类test获得B接口,要实现a这个方法
 
 实现的是接口B的方法a
两个关系:
- 类和接口之间的关系–>>implements实现
 - 接口和接口之间的关系–>>extends拓展
 
接口之间的继承相当于把多个接口并在一起
接口使用实例
    public static void main(String[] args) {int a = 10;int b = 20;System.out.println(a>b);}
 

public class Test {public static void main(String[] args) {Person person01 = new Person();Person person02 = new Person();System.out.println(person01>person02);}
}class Person {public String name;public int age;public int height;
}
 
引用类型比较就不可以了,因为比较两个引用类型没有意义,但是你想比较引用类型里的成员变量的话,他也不知道是哪一个
public class Test {public static void main(String[] args) {Person person01 = new Person();Person person02 = new Person();System.out.println(person01.compareTo(person02));}
}class Person implements Comparable<Person>{public String name;public int age;public int height;@Overridepublic int compareTo(Person o) {if(this.age>o.age) {return 1;} else if(this.age==o.age) {return 0;}else {return -1;}}
}
 
后续文章会讲,此处仅供参考
但是如果用如上代码,在比较身高等其他值的时候就不方便
public class Test {public static void main(String[] args) {Person person01 = new Person("张三",1,1);Person person02 = new Person("李四",2,2);System.out.println(new AgeCompare().compare(person01, person02));}
}class AgeCompare implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {return o1.age-o2.age;}
}class Person{public String name;public int age;public int height;public Person(String name, int age, int height) {this.name = name;this.age = age;this.height = height;}
}
 
比较器来进行年龄比较,之后同样的方法比较身高等
第一种方式比较对类的侵入性比较强,一旦写好了规定的比较方式,之后只能使用这种方式来进行比较
 第二种方式就会比较灵活,单独创建一个类实现比较方法,调用方法时,传入要比较的两个对象即可
public class Test {public static void main(String[] args) {Person[] people = new Person[3];people[0] = new Person(111,"a");people[1] = new Person(101,"b");people[2] = new Person(121,"c");System.out.println(Arrays.toString(people));System.out.println("===========================");Arrays.sort(people);System.out.println("===========================");System.out.println(Arrays.toString(people));}
}class Person {@Overridepublic String toString() {return "Person{" +"age=" + age +", name='" + name + '\'' +'}';}int age;String name;Person(int age, String name) {this.age = age;this.name = name;}
} 
同理,对自定义类型的数组排序此处也会报错
 
 Array.sort的源代码追根溯源发现比较是依托compareTo来实现比较的,所以我们可以在类里自己实现compareTo方法
public class Test {public static void main(String[] args) {Person[] people = new Person[3];people[0] = new Person(111,"a");people[1] = new Person(101,"b");people[2] = new Person(121,"c");System.out.println(Arrays.toString(people));System.out.println("===========================");Arrays.sort(people);System.out.println("===========================");System.out.println(Arrays.toString(people));}
}class Person implements Comparable<Person>{@Overridepublic String toString() {return "Person{" +"age=" + age +", name='" + name + '\'' +'}';}int age;String name;Person(int age, String name) {this.age = age;this.name = name;}@Overridepublic int compareTo(Person o) {return this.age-o.age;}
}
 

 sort方法的重载中还可以传入比较器
public class Test {public static void main(String[] args) {Person[] people = new Person[3];people[0] = new Person(111,"a");people[1] = new Person(101,"b");people[2] = new Person(121,"c");System.out.println(Arrays.toString(people));
//        Arrays.sort(people);AgeCompare ageCompare = new AgeCompare();Arrays.sort(people,ageCompare);System.out.println("===========================");System.out.println(Arrays.toString(people));}
}
//名字比较器
class NameCompare implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {return o2.name.compareTo(o1.name);}
}
//年龄比较器
class AgeCompare implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {return o2.age-o1.age;}
}class Person implements Comparable<Person>{@Overridepublic String toString() {return "Person{" +"age=" + age +", name='" + name + '\'' +'}';}int age;String name;Person(int age, String name) {this.age = age;this.name = name;}@Overridepublic int compareTo(Person o) {return this.name.compareTo(o.name);}
} 
也可以自己实现排序方法来进行比较,如下
public class Test {public static void bubbleSort(Comparable[] comparables) {for (int i = 0; i < comparables.length-1; i++) {for (int j = 0; j < comparables.length-i-1; j++) {if(comparables[j].compareTo(comparables[j+1])>0) {Comparable tem = comparables[j];comparables[j] = comparables[j+1];comparables[j+1] = tem;}}}}public static void main(String[] args) {Person[] people = new Person[3];people[0] = new Person(111,"a");people[1] = new Person(101,"b");people[2] = new Person(121,"c");System.out.println(Arrays.toString(people));bubbleSort(people);System.out.println(Arrays.toString(people));}
}class Person implements Comparable<Person>{@Overridepublic String toString() {return "Person{" +"age=" + age +", name='" + name + '\'' +'}';}int age;String name;Person(int age, String name) {this.age = age;this.name = name;}@Overridepublic int compareTo(Person o) {return this.age-o.age;}
}
 
Clonable接口和深拷贝
public class Test {public static void main(String[] args) {Animal animal = new Animal("张三",10);Animal animal1 = animal.clone();}
}class Animal {String name;int height;@Overridepublic String toString() {return "Animal{" +"name='" + name + '\'' +", height=" + height +'}';}public Animal(String name, int height) {this.name = name;this.height = height;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
 

 创建了一个Animal类,实例化对象animal,想利用clone克隆animal到animal1,但是发生报错
 
 可能会抛出异常,这个异常叫作不支持克隆异常
 编译时期的异常
处理这种异常,对main函数也申请如上操作
 
 发现依旧报错

 观察clone方法里返回值是Object,但是main方法里animal1是Animal类,类型不匹配,需要强转一下
 对main方法如下处理解决刚才的异常问题
public class Test {public static void main(String[] args) throws CloneNotSupportedException{Animal animal = new Animal("张三",10);Animal animal1 = (Animal)animal.clone();}
} 
按照剧本来走的话
 
 animal1克隆animal,一切祥和
public class Test {public static void main(String[] args) throws CloneNotSupportedException{Animal animal = new Animal("张三",10);Animal animal1 = (Animal)animal.clone();System.out.println(animal);System.out.println(animal1);}
}
 
运行起来却又报错
 
 我们要想对自己写的类型进行克隆的时候,要实现Clonable 接口
 
 
 运行成功,但是当我们点进Clonable 接口去看源代码的时候
 
 就会发现这个接口是空的,所以我们实现这个接口的意义在哪里
 刚才这种接口我们叫作空接口或者标记接口
 他的作用在于类实现了Clonable 接口这种空接口,代表这个类是可以被克隆的
public class Test {public static void main(String[] args) throws CloneNotSupportedException{Stu stu = new Stu("张三",1);Stu stu1 = (Stu)stu.clone();System.out.println(stu.index.i);System.out.println(stu1.index.i);stu1.index.i = 0;System.out.println(stu.index.i);System.out.println(stu1.index.i);}
}class Index {public int i = 1;
}class Stu implements Cloneable{public String name;public int weight;Index index = new Index();public Stu(String name, int weight) {this.name = name;this.weight = weight;}@Overridepublic String toString() {return "Stu{" +"name='" + name + '\'' +", weight=" + weight +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
 

 修改stu1里通过引用修改对象index里的成员变量i,但是stu里index的i值也改变
 
 stu1克隆stu,stu和stu1两者共用同一个引用,而非另外开辟空间,所以当你通过引用改变stu1里index的i值时,也时改变stu里面index的i值,这种是浅拷贝,要实现stu里index和stu1里的index的引用不同,要进行深拷贝,Index也要支持克隆

如上,让Index也支持克隆,但这样仅仅是支持克隆,但是并未让Stu类里的克隆方法里进行实现对index的克隆,如下
 
 这样就之后,改变stu1里index的i值就不会影响stu的了
 
public class Test {public static void main(String[] args) throws CloneNotSupportedException{Stu stu = new Stu("张三",1);Stu stu1 = (Stu)stu.clone();System.out.println(stu.index.i);System.out.println(stu1.index.i);stu1.index.i = 0;System.out.println(stu.index.i);System.out.println(stu1.index.i);}
}class Index implements Cloneable{public int i = 1;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}class Stu implements Cloneable{public String name;public int weight;Index index = new Index();public Stu(String name, int weight) {this.name = name;this.weight = weight;}@Overridepublic String toString() {return "Stu{" +"name='" + name + '\'' +", weight=" + weight +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {Stu tmp = (Stu) super.clone();tmp.index = (Index) this.index.clone();return tmp;}
}
 
抽象类和接口的区别
**核心区别:**抽象类中可以包含普通方法和普通字段,这样的普通方法和字段可以被子类直接使用(不需要重写),而接口中不能包含普通方法,子类必须重写所有的抽象方法

Object类
Object是Java默认提过的一个类.Java里面除了Object类,所有的类都是存在继承关系的.默认会继承Object父类,即所有类的对象都可以使用Object的引用进行接收.
public class Test {public static void main(String[] args){Animal animal = new Animal("张三");Animal animal1 = new Animal("张三");System.out.println(animal1 == animal);}
}class Animal {String name;public Animal(String name) {this.name = name;}
}
 
如上比较两个对象是否相等,这种比较是比较引用,所以会打印false
 Object里equals方法用来比较对象是否相等
 
public class Test {public static void main(String[] args){Animal animal = new Animal("张三");Animal animal1 = new Animal("张三");System.out.println(animal.equals(animal1));}}
 

 结果仍是false

 源码和第一次比较方式是一样的,在对引用进行比较相等,所以我们在Animal类里重写这个方法,自己来设计比较方法
class Animal {String name;public Animal(String name) {this.name = name;}@Overridepublic boolean equals(Object obj) {Animal animal = (Animal) obj;return animal.name.equals(this.name);}
}
 
public class Test {public static void main(String[] args){Animal animal = new Animal("张三");Animal animal1 = new Animal("张三");System.out.println(animal.equals(animal1));}}
 

 
相关文章:
图灵日记之java奇妙历险记--抽象类和接口
目录 抽象类概念抽象类语法 接口概念规则使用特性实现多个接口接口的继承接口使用实例Clonable接口和深拷贝抽象类和接口的区别 Object类 抽象类 概念 在面向对象的概念中,所有对象都是通过类来描述的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够…...
批量给元素添加进场动画;获取文本光标位置;项目国际化
批量给元素添加进场动画 api及参数参考:https://juejin.cn/post/7310977323484971071 简单实现: addAnimationClass(){//交叉观察器if (window?.IntersectionObserver) {//获取所有需要添加进场动画的元素,放到一个数组let items [...do…...
解决:docker创建Redis容器成功,但无法启动Redis容器、也无报错提示
解决:docker创建Redis容器成功,但无法启动Redis容器、也无报错提示 一问题描述:1.docker若是直接简单使用run命令,但不挂载容器数据卷等参数,则可以启动Redis容器2.docker复杂使用run命令,使用指定redis.co…...
Jlink+OpenOCD+STM32 Vscode 下载和调试环境搭建
对于 Mingw 的安装比较困难,国内的网无法正常在线下载组件, 需要手动下载 x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z 版本的软件包,添加环境变量,并将 mingw32-make.exe 名字改成 make.exe。 对于 OpenOCD,需要…...
单片机在物联网中的应用
单片机,这个小巧的电子设备,可能听起来有点技术性,但它实际上是物联网世界中的一个超级英雄。简单来说,单片机就像是各种智能设备的大脑,它能让设备“思考”和“行动”。由于其体积小、成本低、功耗低、易于编程等特点…...
16.Qt 工具栏生成
目录 前言: 技能: 内容: 1. 界面添加 2. 信号槽 功能实现 参考: 前言: 基于QMainWindow,生成菜单下面的工具栏,可以当作菜单功能的快捷键,也可以完成新的功能 直接在UI文件中…...
【Linux内核】从0开始入门Linux Kernel源码
🌈 博客个人主页:Chris在Coding 🎥 本文所属专栏:[Linux内核] ❤️ 前置学习专栏:[Linux学习]从0到1 ⏰ 我们仍在旅途  目录 …...
SQL Service 2008 的安装与配置
点击添加当前用户...
Apache POI | Java操作Excel文件
目录 1、介绍 2、代码示例 2.1、将数据写入Excel文件 2.2、读取Excel文件中的数据 🍃作者介绍:双非本科大三网络工程专业在读,阿里云专家博主,专注于Java领域学习,擅长web应用开发、数据结构和算法,初步…...
vue 学习definproperty方法
definproperty方法是Vue很重要的一个底层方法,掌握他的原理很重要,下面通过代码说明问题: <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>回顾Object.defineproperty方法</title&…...
react 实现路由拦截
简单介绍下项目背景,我这里做了一个demo,前端使用mock数据,然后实现简单的路由拦截,校验session是否包含用户作为已登录的依据,react-router-dom是v6。不像vue可以设置登录拦截beforeenter,react需要我们自…...
数据分析(一) 理解数据
1. 描述性统计(summary) 对于一个新数据集,首先通过观察来熟悉它,可以打印数据相关信息来大致观察数据的常规特点,比如数据规模(行数列数)、数据类型、类别数量(变量数目、取值范围…...
什么是 Flet?
什么是 Flet? Flet 是一个框架,允许使用您喜欢的语言构建交互式多用户 Web、桌面和移动应用程序,而无需前端开发经验。 您可以使用基于 Google 的 Flutter 的 Flet 控件为程序构建 UI。Flet 不只是“包装”Flutter 小部件,而是…...
多模态(三)--- BLIP原理与源码解读
1 BLIP简介 BLIP: Bootstrapping Language-Image Pre-training for Unified Vision-Language Understanding and Generation 传统的Vision-Language Pre-training (VLP)任务大多是基于理解的任务或基于生成的任务,同时预训练数据多是从web获…...
掌握高性能SQL的34个秘诀多维度优化与全方位指南
掌握高性能SQL的34个秘诀🚀多维度优化与全方位指南 本篇文章从数据库表结构设计、索引、使用等多个维度总结出高性能SQL的34个秘诀,助你轻松掌握高性能SQL 表结构设计 字段类型越小越好 满足业务需求的同时字段类型越小越好 字段类型越小代表着记录占…...
美国纳斯达克大屏怎么投放:投放完成需要多长时间-大舍传媒Dashe Media
陕西大舍广告传媒有限公司(Shaanxi Dashe Advertising Media Co., Ltd),简称大舍传媒(Dashe Media),是纳斯达克在中国区的总代理(China General Agent)。与纳斯达克合作已经有八年的…...
【MySQL】多表关系的基本学习
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-3oES1ZdkKIklfKzq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…...
Springboot之接入gRPC
1、maven依赖 <properties><!-- grpc --><protobuf.version>3.5.1</protobuf.version><protobuf-plugin.version>0.6.1</protobuf-plugin.version><grpc.version>1.42.1</grpc.version><os-maven-plugin.version>1.6.0…...
2023年中国数据智能管理峰会(DAMS上海站2023):核心内容与学习收获(附大会核心PPT下载)
随着数字经济的飞速发展,数据已经渗透到现代社会的每一个角落,成为驱动企业创新、提升治理能力、促进经济发展的关键要素。在这样的背景下,2023年中国数据智能管理峰会(DAMS上海站2023)应运而生,汇聚了众多…...
DS:八大排序之堆排序、冒泡排序、快速排序
创作不易,友友们给个三连吧!! 一、堆排序 堆排序已经在博主关于堆的实现过程中详细的讲过了,大家可以直接去看,很详细,这边不介绍了 DS:二叉树的顺序结构及堆的实现-CSDN博客 直接上代码: …...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
