Java抽象类和接口(1)

🐵本篇文章将对抽象类接口相关知识进行讲解


一、抽象类

先来看下面的代码:

class Shape {public void draw() {System.out.println("画");}
}
class Cycle extends Shape {public void draw() {System.out.println("圆形");}
}
public class Test2 {public static void main(String[] args) {Shape shape = new Cycle(); shape.draw();}
}

在上述代码中,Shape类中的draw方法,因为有动态绑定而始终没有被实现,且Shape类不能描绘某个具体的对象,我们可以将这样不能描绘某个具体对象的类设为抽象类,具体操作是:使用abstract关键字修饰这个类,此时这个类被称为抽象类,可以将抽象类中被重写的方法也用abstract修饰,此时这个方法就叫抽象方法,抽象方法不能有具体实现

abstract class Shape {public abstract void draw();
}
class Cycle extends Shape {public void draw() {System.out.println("圆形");}
}

二、抽象类相关总结

1. 抽象方法所在类必须是抽象类,抽象类不一定包含抽象方法

2. 抽象类中可以有和非抽象成员变量和成员方法(和普通类一样)

3. 抽象类不能被实例化

abstract class Shape {public abstract void draw();
}
class Cycle extends Shape {public void draw() {System.out.println("圆形");}
}
public class Test2 {public static void main(String[] args) {Shape shape = new Shape();//编译报错:抽象类不能被实例化}
}

4. 抽象类必须被继承,普通类继承抽象类后,必须重写抽象类中的抽象方法,(如果抽象类中没有抽象方法则可以不用重写)如果继承抽象类的也是抽象类则不用重写

5. 抽象方法不能被privatefinalstatic修饰

6. 在多层继承关系下,子类必须继承所有父类的抽象方法

abstract class A {public abstract void print();
}
abstract  class B extends A {public abstract void test();
}
class C extends B {//必须重写print和test方法,否则编译报错public void print() {}public void test() {}
}

7. 抽象类也有构造方法,只不过是被子类调用并帮助其初始化(因为抽象类不能实例化对象)

abstract class A {public abstract void print();public A() {}
}
class B extends A {public B() {super();}public void print() {}
}

三、接口

3.1 创建接口

创建一个接口需要用到interface关键字

interface 接口名 {

}

3.2 接口的使用

类和接口之间的关系是实现,即类实现接口,具体操作是使用implements关键字实现

类名 implements 接口名 {

}

下面举一个实例:

interface IUsb {void openDevice(); //默认为抽象方法void closeDevice();
}class Mouse implements IUsb {public void openDevice() {System.out.println("打开鼠标");}public void closeDevice() {System.out.println("关闭鼠标");}public void clink() {System.out.println("点击鼠标");}
}class Keyboard implements IUsb {@Overridepublic void openDevice() {System.out.println("打开键盘");}@Overridepublic void closeDevice() {System.out.println("关闭键盘");}public void inPut() {System.out.println("键盘输入");}
}class Computer {public void powerOn() {System.out.println("开机");}public void powerOff() {System.out.println("关机");}public void useDevice(IUsb iUsb) {iUsb.openDevice(); //这里实现了多态if (iUsb instanceof Mouse) { //判断iUsb是否引用Mouse对象Mouse mouse = new Mouse(); //向下转型mouse.clink();} else if (iUsb instanceof Keyboard) {Keyboard keyboard = new Keyboard(); //向下转型keyboard.inPut();}iUsb.closeDevice();}
}public class Test {public static void main(String[] args) {Computer computer = new Computer();computer.powerOn();computer.useDevice(new Mouse()); //向上转型computer.useDevice(new Keyboard()); //向上转型computer.powerOff();}
}

3.3 接口相关总结

1. 接口中定义的成员变量默认被public static final修饰,定义的成员方法默认被public abstract修饰

2. 接口中的方法如果没有具体实现则默认为抽象方法

3. 接口中的方法一般不能具体实现(没有方法块)如果要具体实现,应由defaultstatic修饰

interface IUsb {default void method() {System.out.println("实现method方法");}static void method1() {System.out.println("实现method1方法");}
}

4. 接口不能被实例化

interface IShape {
}
public class Test1 {public static void main(String[] args) {IShape iShape = new IShape();//编译报错:接口不能被实例化对象}
}

5. 一个类可以继承一个普通类/抽象类,同时还可以实现接口

interface A {}
class B {}
class C extends B implements A { //必须先继承在实现
}

6. 一个类实现一个接口后,必须重写其内部的方法

四、实现多接口

在Java中不支持多继承,但可以实现多接口,即一个类可以实现多个接口

class 类名 implements 接口名,接口名, ... {
}

实际上多接口就是为了解决Java中不能多继承的问题,下面举一个例子:

interface IRun {void run();
}interface ISwim {void swim();
}class Dog implements IRun, ISwim {
//实现这两个接口后,要重写接口中的抽象方法public void run() {System.out.println("跑");}public void swim() {System.out.println("游");}
}

将run()和swim()两个方法分别写到两个接口中而不是直接将这两个方法写到一个Animal类中让Dog类来继承的原因是:将来如果有其它类比如一个Bird类要继承Animal类,那就会直接将Animal类中所有的方法全部继承,但是“鸟不能游泳”所以这样写不符合逻辑

五、接口间的继承

Java中类和类之间不支持多继承,但接口和接口之间是支持多继承的

interface IJump {void jump();
}interface ISing {void sing();
}interface IRap extends IJump, ISing { }class Student implements IRap{@Overridepublic void jump() {}@Overridepublic void sing() {}
}

接口间的继承的意义就是将多个接口合并为一个接口

六、Object类

object类是所有类的父类 

class Person {public String name;public Person(String name) {this.name = name;}
}public static void main(String[] args) {public static void func(Object obj) { System.out.println(obj); //这里会调用Object类中toString中的方法,打印obj所指对象的地址}public static void main(String[] args) {func(new Person("Sans")); //向上转型}    
}     

调用Object类中toString方法的源码顺序:

    public void println(Object x) { String s = String.valueOf(x); //调用valueof方法synchronized (this) {print(s);newLine();}}public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); //若obj指向某个对象则调用toString方法}public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode());}   //返回对象的地址

6.1 equals方法

equals方法是Object类中的成员方法,在此之前先来回顾一下“==”

如果==左右两侧是基本类型变量,比较的是变量中值是否相同
如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同

equals的源码如下:

public boolean equals(Object obj) {return (this == obj);
}

下面举一个实例:

class Person {public String name;public Person(String name) {this.name = name;}
}public class Test {public static void main(String[] args) {func(new Person("Sans"));Person person1 = new Person("Sans");Person person2 = new Person("Sans");System.out.println(person1.equals(person2));//由于person1和person2指向不同对象,所以它们的地址不同
}

如果要使用equals方法比较对象的内容,则需要在Person类中重写equals方法,

class Person {public String name;public Person(String name) {this.name = name;}public boolean equals(Object obj) {Person per = (Person) obj;return per.name.equals(this.name); //name是String类型,String类继承了object类同时也重写了equals方法//所以这里是调用了String类的方法}}public class Test {public static void main(String[] args) {Person person1 = new Person("Sans");Person person2 = new Person("Sans");System.out.println(person1.equals(person2));//Person类继承了object类并重写了equals方法,所以这里//发生动态绑定,调用子类即Person类的equals方法
}

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

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

相关文章

开发知识点-ArkTS-鸿蒙开发-Typescript

Typescript IED IED https://developer.harmonyos.com/cn/develop/deveco-studio/#download

打开CMD的六种方法,CMD快捷键,CMD命令大全及详解

目录 前言1. winR快捷键2、通过文本文档创建;3、通过C盘中的cmd.exe文件打开;4、创建快捷方式;5、通过PowerShell打开;6、通过文件夹导航栏打开; 前言 自己的电脑win键失灵了,想通过winR来调出cmd&#xff…

【Linux基础】Linux常见指令总结及周边小知识

前言 Linux系统编程的学习我们将要开始了,学习它我们不得不谈谈它的版本发布是怎样的,谈它的版本发布就不得不说说unix。下面是unix发展史是我在百度百科了解的 Unix发展史 UNIX系统是一个分时系统。最早的UNIX系统于1970年问世。此前,只有…

Doris单机部署——2.0.1.1版本

目录 一、前期准备工作 1.设置系统最大文件打开句柄数 2.时钟同步 3.关闭每台机器的交换分区 4.下载安装包 二、单节点部署安装Doris (一)安装fe 1.解压改名 2.修改配置文件 3.创建元数据目录 4.启动fe 5.访问fe的webUI (二)安装be 1.进入be目录下,修…

Leetcode—35.搜索插入位置【简单】

2023每日刷题&#xff08;四十&#xff09; Leetcode—35.搜索插入位置 实现代码 int lower_bound(int* arr, int numsSize, int tar) {int left 0, right numsSize;int mid;// 左闭右开[left, right)while(left < right) {mid left (right - left) / 2;if(arr[mid] &…

Cadence Vmanager vsif文件编写指南(持续更新...)

目录 1.NTF格式介绍 1.1.1 {属性&#xff1a;值}定义 1.1.2类别 1.1.3语法 2.vsif文件中有效的container 2.1 session {…} 1.NTF格式介绍 Cadence的Vmanager工具采用vsif类型的文件作为regression的输入文件&#xff0c;采用vplanx/csv类型的文件作为vplan的输入文件&am…

BC77 简单计算器(牛客)

#include <stdio.h> int main() {double a, b, d;//用来接收浮点数char c;//用来接受符号scanf("%lf %c %lf", &a, &c, &b);if (c || c - || c * || c /)//判断输入的运算符号不包括在&#xff08;、-、*、/&#xff09;范围内{switch (c)//根…

Kotlin应用——使用kt进行web开发 使用h2database进行初始化数据库 mybatis-plus使用

Kotlin 是一门现代但已成熟的编程语言&#xff0c;旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作&#xff0c;并提供了多种方式在多个平台间复用代码&#xff0c;以实现高效编程。 kt入门的合集文章如下&#xff1a; Kotlin学习——kt入门合集博客 &…

P16 C++构造函数

目录 前言 01 什么是构造函数呢&#xff1f; 02 非构造函数初始化变量 03 构造函数初始化变量 04 带参数的构造函数。 最后的话 前言 我们继续学习 C 的面向对象编程&#xff0c;本章主要是讲其中的 构造函数。 01 什么是构造函数呢&#xff1f; 构造函数基本上是一种特…

tinyViT论文笔记

论文&#xff1a;https://arxiv.org/abs/2207.10666 GitHub&#xff1a;https://github.com/microsoft/Cream/tree/main/TinyViT 摘要 在计算机视觉任务中&#xff0c;视觉ViT由于其优秀的模型能力已经引起了极大关注。但是&#xff0c;由于大多数ViT模型的参数量巨大&#x…

MetaObject-BeanWrapper-MetaClass-Reflector的关系

MetaObject、BeanWrapper、MetaClass、Reflector之间是通过装饰器模式逐层进行装饰的。其中MetaObject、BeanWrapper是操作对象&#xff1b;MetaClass、Reflector是操作Class ObjectWrapper类结构图 BaseWrapper是对BeanWrapper、MapWrapper公共方法的提取及类图的优化&#…

线程的创建方式

作者简介&#xff1a; zoro-1&#xff0c;目前大二&#xff0c;正在学习Java&#xff0c;数据结构&#xff0c;mysql&#xff0c;javaee等 作者主页&#xff1a; zoro-1的主页 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f496; 线程的创建方…

知识点小总结

‘Integer(int)‘ 已经过时了 https://blog.csdn.net/qq_43116031/article/details/127793512 解决Java中的“找不到符号“错误 解决Java中的“找不到符号“错误_java: 找不到符号_很酷的站长的博客-CSDN博客 可右键打开 错误: 编码 UTF-8 的不可映射字符 错误: 编码 UTF-8 …

Less的函数的介绍

文章目录 前言描述style.less输出后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#xff0c;…

什么是无监督学习

1 概况 1.1 定义 无监督学习&#xff08;Unsupervised Learning&#xff09;是机器学习的一种类型&#xff0c;它涉及从未标记的数据中发现隐藏的模式。与监督学习不同&#xff0c;无监督学习的数据没有显式的标签或已知的结果变量。其核心目的是探索数据的内在结构和关系。无…

Less 嵌套规则

文章目录 前言描述style.less输出后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#xff0c;…

数据库基础教程之创建触发器,实现自动更新时间戳(四)

postgresql 更新时间戳需要通过触发器来实现,这里给出两种方法来实现。 创建字段create_time和edit_time 通过Navicat在添加字段时候将字段设置为timestamp类型,生成时间戳方式为CURRENT_TIMESTAMP或者设置为now(),然后点击保存。 新建函数 点击函数,然后在弹出的函数向导中…

RabbitMQ之MQ的可靠性

文章目录 前言一、数据持久化交换机持久化队列持久化消息持久化 二、LazyQueue控制台配置Lazy模式代码配置Lazy模式更新已有队列为lazy模式 总结 前言 消息到达MQ以后&#xff0c;如果MQ不能及时保存&#xff0c;也会导致消息丢失&#xff0c;所以MQ的可靠性也非常重要。 一、…

将本地项目上传到gitee

本文详细介绍如何将本地项目上传到gitee 1.登录gitee创建一个与本地项目名相同的仓库 2.进入本地项目所在路径&#xff0c;打开Git Bash 3.执行初始化命令 git init4.添加远程仓库 4.1 点击复制你的HTTPS仓库路径 4.2 执行添加远程仓库命令 git remote add origin 你的…

Vue常见的实现tab切换的两种方法

目录 方法一&#xff1a;事件绑定属性绑定 效果图 完整代码 方法二&#xff1a;属性绑定 动态组件 component标签 效果图 完整代码 方法一&#xff1a;事件绑定属性绑定 效果图 完整代码 <!DOCTYPE html> <html lang"en"> <head><meta c…