Java类和对象(五)—— 抽象类、接口、Object类和内部类
抽象类
在继承体系下,父类有些方法可能是要被重写的,如果我们事先就知道某些方法需要重写的话,我们可以不用在父类里面具体实现这个方法,这时候我们会用到抽象方法,这时候我们会用到关键字abstract关键字来修饰
public abstract class Animal {protected abstract void eat();
}
例如上面的Animal 类,每一个动物都会吃,但是每一个动物却吃的食物不同,父类的eat方法无法完全描述某个对象,这时候子类就需要重写这个方法,如果我们不想在父类具体实现这个eat方法的话,我们可以写成抽象方法~~
说完抽象方法,我们来类比一下抽象类:
如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类
抽象类也是用abstract 修饰的~~
注意要点
有抽象方法的类,一定是抽象类,所以如果方法被abstract修饰,那类也必须由abstract修饰,否则编译报错
抽象类是不能进行实例化的,但是可以有继承的向上转型和向下转型~~
被private、static、final 修饰的方法不能是抽象方法
因为抽象方法就是为了被子类重写的,根据重写的规则,被private、static、final修饰的方法确实不能被重写
抽象类被继承后,继承后子类要重写父类中的抽象方法,除非子类也是抽象类,必须要使用 abstract 修饰,无论是谁继承了抽象类都必须重写所有的抽象方法,否则编译报错~~
当Dog继承Animal,必须重写Aniaml所有的抽象方法~~
如果Dog还是抽象类,Cat 继承 Dog,并且在 Cat 不是抽象的情况下,我们要在 Cat 这个类重写所有的抽象方法(即包括 Animal 也包括 Dog 的抽象方法)
抽象类的作用
抽象类就是用来被继承的
谁继承了抽象类,都必须重写抽象方法,否则编译报错,这也是为了多加一层编译器的校验
接口
接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。
在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型
我们使用 intarface 来定义接口,就是把class替换成interface
public interface Ieat {void eat();
}
接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
接口的使用规则
接口的成员方法是默认都是public static final 修饰的
接口的成员方法默认都是 public abstract 修饰的
当你在接口里定义了一个成员变量的时候,你必须对其进行初始化!!!
如果你想具体实现某些方法,你可以使用 static 或者 default 来进行修饰:
public interface Ieat {static void eat(){//...}default void eat2(){//...}
}
访问权限也是和之前讲的是一样的,被static就是默认权限的静态方法,被default 修饰就是默认访问权限。
接口不能有实例化代码块、静态代码块,也不能有构造方法~~
如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类,如果被继承就必须重写所有的抽象方法!!!
这个和抽象类是类似的~~
软性规则:
创建接口时, 接口的命名一般以大写字母 I 开头.
接口的命名一般使用 “形容词” 词性的单词.
阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性.
接口的继承
接口与接口之间可以多继承。即:用接口可以达到多继承的目的。
接口可以继承一个或者多个接口, 达到复用的效果. 使用 extends 关键字。
interface IA{void eat();
}interface IB{void sleep();
}interface C extends IA,IB{}
接口的作用
解决了 Java 不能多继承的问题!!!
意味着一个类可以有多个接口!!!
如果子类由继承父类还有多个接口的时候,我们要先继承后接口(先extends 再 implements)
快捷键(搭建接口当中的抽象方法)
IDEA 中使用 ctrl + i 快速搭建接口当中的抽象方法~~
或者使用 alt + enter 进行选择implements methods 进行快速搭建接口,你选择Make ‘Dog’ abstract 的话就是讲这个类变为抽象类~~
接口的好处
public class Animal {protected String name;protected int age;
}public interface Irun {void run();
}public class Cat extends Animal implements Irun{public Cat(String name, int age) {this.name = name;this.age = age;}@Overridepublic void run() {System.out.println(this.name + "正在跑步");}
}public class Dog extends Animal implements Irun{public Dog(String name, int age) {this.name = name;this.age = age;}@Overridepublic void run() {System.out.println(this.name + "正在跑步");}
}public class Test {public static void walk(Irun irun){irun.run();}public static void main(String[] args) {walk(new Dog("旺财",11));walk(new Cat("小咪",10));}
}
接口也可以有动态绑定和多态~~
由于接口可以实现多态,所以程序员可以不关注类型,只要有这个接口的类,都能调用里面的接口方法,而不用去关心这是什么类。
Object 类
Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父类。即所有类的对象都可以使用Object的引用。
我们这里先重点关注一下上面标出来的三个方法:toString,equals,hashCode,
toString(打印对象)
class Person{public String name;public int age;}public class Test {public static void main(String[] args) {Person person = new Person();System.out.println(person);}
}
我们在数组里知道直接打印数组名的话会出现包含数组的地址的一串字符串~~
如果直接打印对象的话,也会出现和数组类似的情况,这是为什么?
Java所有的类都会继承Object类,在调用println的时候,我们来看看一共调用了哪些方法:
首先println 方法如下:
之后无论是走if 语句还是else 语句,都会调用toString方法
最后就会来到toString 方法,这里getClass.getName()就是类名,然后加@符号,最后调用hashCode找到地址。
但是如果我们重写了 toString 方法的话,根据前面的知识,优先调用子类的方法来打印对象内容。
class Person{public String name;public int age;@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}
这样的话,我们就会优先调用子类自己的toString 方法
我们可以使用编译器自动生成toString方法:
和之前搭建getter、setter还有构造方法是一样的,只是这里选择的是toString()
class A{public String name;public int age;@Overridepublic String toString() {return "A{" +"name='" + name + '\'' +", age=" + age +'}';}
}
equals
在Java当中,如果使用 == 来进行比较时
如果比较的是基本数据类型的话,就是比较两个的数值相不相同
如果比较的是引用数据类型,就会比较他们的地址相不相同
来我们看一下源码:
还是一样的,直接调用equals方法,还是比较两个对象的地址,所以如果想比较两个对象的内容相不相同就必须重写equals方法~~
public boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}
class Person{public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}
}public class Test {public static void main(String[] args) {Person person1 = new Person("张三",10);Person person2 = new Person("张三",10);System.out.println(person1.equals(person2));}
}
比较对象中内容是否相同的时候,一定要重写equals方法。
hashCode
源码:
native 说明这是本地方法,这个是有C/C++代码编写的,我们是看不到的
简单来说,hashCode方法可以找到对象的内存地址
public class Test {public static void main(String[] args) {Person person1 = new Person("张三",10);Person person2 = new Person("张三",10);System.out.println(person1.hashCode());System.out.println(person2.hashCode());}
}
由于这是两个不同的对象,所以他们的内存地址是不一样的~~
但是如果我们认为当两个对象的内容是一样的,那地址就应该是一样的话,我们就需要重写hashCode 方法~~
@Overridepublic int hashCode() {return Objects.hash(name, age);}
这样他们的地址就会是一样的显示~~
快捷键搭建
以上三个方法都能使用快捷键快速搭建:
内部类
内部类就是在类里面再定义一个类,这个类定义的位置和外部类的成员是相同的。
静态内部类
被static修饰的内部成员类称为静态内部类。
class A{public int age;public static int price;public A(){System.out.println("A()......");}public void methodA1(){System.out.println("methodA1()......");}public static void methodA2(){System.out.println("methodA2()......");}static class B{public void methodB(){//age = 10;//err,静态内部类只能访问外部类的静态成员//A();//不要在静态内部类中调用外部类的构造方法,构造方法是没有静态的,所以构造方法一定不是静态方法//methodA1(); //err,静态内部类只能访问外部类的静态成员,methodA1不是类方法(静态成员方法)price = 10;methodA2();}}//.....
}
注意事项
静态内部类只能访问外部类的静态成员
创建静态内部类
A.B b = new A.B();
我们可以将静态内部类当成外部类的一个静态成员,静态成员的访问不需要创建对象,我们可以通过类名来访问,于是我们通过 A.B 就访问到了静态内部类,然后就通过new A.B 就可以完成创建了
实例内部类
未被static 修饰的实例内部类就是实例内部类
实例内部类可以自由访问外部类的任意成员,如果实例内部类和外部类有重名的成员时,在内部类中优先访问自己的,如果真的相访问外部类同名的成员时,我们可以使用 外部类类名.this.成员 即可~~
class A{public int age;public static int price;public A(){System.out.println("A()......");}public void methodA1(){System.out.println("methodA1()......");}public static void methodA2(){System.out.println("methodA2()......");}public void methodA3(){System.out.println("methodA3()......");}class C{public int age = 10;public void methodC(){System.out.println(age);methodA3();System.out.println(A.this.age);methodA1();A.this.methodA1();}public void methodA1(){System.out.println("C::methodA1()......");}}//.....
}public class Test{public static void main(String[] args) {A.C c = new A().new C();c.methodC();}
}
创建实例内部类
我们要先创建外部类,再去创建实例内部类
A.C c = new A().new C();
当然也可以分部去写:
A a = new A();
A.C c = a.new C();
注意事项
1.外部类中的任何成员都 可以在实例内部类方法中直接访问
2.实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
3.在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名
称.this.同名成员 来访问
4.实例内部类对象必须在先有外部类对象前提下才能创建
5.实例内部类的非静态方法中包含了一个指向外部类对象的引用
6.外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。
匿名内部类
class A{public void test1(){System.out.println("heihei");}
}public class Test{public static void main(String[] args) {new A(){}.test1();}}
通过后面的 .方法 来调用相应的方法。
我们也可以重写匿名内部类的方法
但是要注意不能使用对象来接收匿名内部类
接口也可以使用:
interface A{void test1();
}public class Test{public static void main(String[] args) {new A(){public void test1(){System.out.println("haha");}};}}
和上面不一样的是,接口是一定要重写其中的抽象方法的,并且花括号后面是不能直接 .方法 的,而是要通过被接收后,然后去再去调用相应的方法~~
因此接口是可以被接收的,接收后也是可以继续使用的:
局部内部类
局部内部类是定义在方法里的,因此它的生命周期和方法是一样。
public void A() {//...class D{ //......}//...}
相关文章:

Java类和对象(五)—— 抽象类、接口、Object类和内部类
抽象类 在继承体系下,父类有些方法可能是要被重写的,如果我们事先就知道某些方法需要重写的话,我们可以不用在父类里面具体实现这个方法,这时候我们会用到抽象方法,这时候我们会用到关键字abstract关键字来修饰 publ…...

图像上下文学习|多模态基础模型中的多镜头情境学习
【原文】众所周知,大型语言模型在小样本上下文学习(ICL)方面非常有效。多模态基础模型的最新进展实现了前所未有的长上下文窗口,为探索其执行 ICL 的能力提供了机会,并提供了更多演示示例。在这项工作中,我…...

汇编:函数以及函数参数传递
汇编语言中的函数(或过程)是指一段可以被调用和执行的代码块;它们用于组织和重用代码,并使程序结构更加清晰;由于汇编语言没有高层次语言的语法糖,编写和调用函数涉及直接的堆栈操作和寄存器管理࿱…...
linux-ftp服务器搭建简介
安装ftp服务器: vsftpd全称为“very secure FTP daemon”,是一个在UNIX类操作系统上运行的服务,可以提供高安全性的FTP服务。 vsftpd是一个免费和开放源代码的FTP服务器软件,它提供了许多其他FTP服务器不支持的特性,例…...

二十一、openlayers官网示例Custom Controls解析——自定义控件扩展Control类
官网demo地址: Custom Controls 这个示例讲的是如何自定义控件 首先创建了一个新的类继承了原本的Control,新增了一个button元素,然后调用了super方法将参数传给了父类。 const button document.createElement("button");button.…...

【博主推荐】HTML5实现520表白、情人节表白模板源码
文章目录 1.设计来源1.1 表白首页1.2 甜蜜瞬间11.3 甜蜜瞬间21.4 甜蜜瞬间31.5 甜蜜瞬间41.6 甜蜜瞬间51.7 甜蜜瞬间61.8 永久珍藏 2.效果和源码2.1 页面动态效果2.2 页面源代码2.3 源码目录2.4 更多为爱表白源码 3.源码下载地址 作者:xcLeigh 文章地址:…...

【YOLOv5/v7改进系列】替换激活函数为SiLU、ReLU、LeakyReLU、FReLU、PReLU、Hardswish、Mish、ELU等
一、导言 激活函数在目标检测中的作用至关重要,它们主要服务于以下几个关键目的: 引入非线性:神经网络的基本构建块(如卷积层、全连接层等)本质上是线性变换,而激活函数通过引入非线性,使得网络…...
修改MySQL root用户密码
ALTER USER ‘root’‘localhost’ IDENTIFIED BY ‘new_password’; ALTER USER ‘root’‘%’ IDENTIFIED BY ‘new_password’; 》 SET GLOBAL read_only OFF; select * from mysql.user;...

力扣刷题---409. 最长回文串【简单】
题目描述 给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的回文串 。 在构造过程中,请注意 区分大小写 。比如 “Aa” 不能当做一个回文字符串。 示例 1: 输入:s “abccccdd” 输出:7 解释: 我们可以构造的最长的回文串…...

百度智能云参与信通院多项边缘计算标准编制,「大模型时代下云边端协同 AI 发展研讨会」成功召开
1 中国信通院联合业界制定、发布多项标准化成果,推动产业发展 大模型开启了 AI 原生时代,云边端协同 AI 构建了「集中式大规模训练」、「边缘分布式协同推理」新范式,有效降低推理时延和成本,提升数据安全和隐私性,也…...
前后端联调
网关 网关作用(认证授权、流量控制、路由转发等)网关如何工作(类似前端的路由守卫,访问服务前都经过网关) http状态码 3xx:重定向 301:永久重定向 302:临时重定向 304:…...
根据配置的mode环境显示不同的index模板
引言:在项目开发中,遇到了开发环境和生产环境使用模板不同的情况,配置如下: 一、vue.config.js const path require(path) function resolve(dir){return path.join(__dirname,dir) } module.exports {chainWebpack: config &g…...

hls.js实现分片播放视频
前言:hls.js官网:hls.js - npm 一、demo——在HTML中使用 <audio id"audio" controls></audio><script src"https://cdn.jsdelivr.net/npm/hls.jslatest"></script> <script>document.addEventList…...
K8s 运维架构师实战课程
阿良课程收益 掌握Kubernetes企业运维管理 掌握部署、运维、存储、网络、监控、日志、CICD、服务网格等实战全面搞定! 独立将公司任何项目容器化迁移到K8s平台 生产环境真实案例 大厂企业实战经验 学习最新版、最佳实践 K8s 运维架构师实战【初中级】:ht…...

AIGC基础教学:AI+建筑设计,一场划时代变革的序幕已经拉开
2015年9月,美的集团本着把艺术融入民间的理念,邀请了安藤忠雄设计正在筹建中的美术馆。 在历经长达近120天的设计工作之后,美术馆于同年12月动工。这座具有岭南建筑文化意境的美术馆,后来荣获2020年美国建筑大师奖(Architecture …...

领域知识 | 智能驾驶安全领域部分常见概论
Hi,早。 最近想买个新能源车,这个车吧相比于之前的内燃车,新能源车与外界的交互多了很多。比如娱乐的第三方应用,OTA升级等应用。 交互带来的便利越多,暴露的风险自然也就越大,相比于手机等消费者终端设备…...

力扣刷题---返回word中所有不重复的单词
当需要从一个数据集合中去除重复元素时,set是一个很好的选择。由于其不允许存储重复的元素,因此可以很容易地实现去重功能。这在处理原始数据或进行数据分析时特别有用。 题目: 给定一个字符串数组 words,请返回一个由 words 中所…...

正点原子LWIP学习笔记(一)lwIP入门
lwIP入门 一、lwIP简介(了解)二、lwIP结构框图(了解)三、如何学习lwIP(熟悉) 一、lwIP简介(了解) lwIP是一个小型开源的TCP/IP协议栈 阉割的TCP/IP协议 TCP/IP协议栈结构࿰…...
16、设计模式之迭代器模式
迭代器模式 迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。 迭代器模式属于行为型模式。 介绍 意图: 提供一种方法顺序访问…...

自然语言处理实战项目29-深度上下文相关的词嵌入语言模型ELMo的搭建与NLP任务的实战
大家好,我是微学AI,今天给大家介绍一下自然语言处理实战项目29-深度上下文相关的词嵌入语言模型ELMo的搭建与NLP任务的实战,ELMo(Embeddings from Language Models)是一种深度上下文相关的词嵌入语言模型,它采用了多层双向LSTM编码器构建语言模型,并通过各层LSTM的隐藏状…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器
一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下,音视频内容犹如璀璨繁星,点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频,到在线课堂中知识渊博的专家授课,再到影视平台上扣人心弦的高清大片,音…...

Vue3 PC端 UI组件库我更推荐Naive UI
一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用,前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率,还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库(Naive UI、Element …...