【0基础学Java第九课】-- 抽象类和接口

9. 抽象类和接口

  • 9.1 抽象类
    • 9.1.1 抽象类概念
    • 9.1.2 抽象类语法
    • 9.1.3 抽象类的特性
    • 9.1.4 抽象类的作用
  • 9.2 接口
    • 9.2.1 接口的概念
    • 9.2.2 语法规则
    • 9.2.3 接口使用
    • 9.2.4 接口特性
    • 9.2.5 实现多个接口
    • 9.2.6 接口的继承
    • 9.2.9 抽象类和接口的区别
  • 9.3 Object类
    • 9.3.1 获取对象方法
    • 9.3.1 对象比较equals方法
    • 9.3.2 hashcode方法

9.1 抽象类

9.1.1 抽象类概念

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

在这里插入图片描述
在这里插入图片描述

在打印图形例子中, 我们发现, 父类 Shape 中的 draw 方法好像并没有什么实际工作, 主要的绘制图形都是由 Shape的各种子类的 draw 方法来完成的. 像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstract method), 包含抽象方法的类我们称为** 抽象类(abstract class)**.

9.1.2 抽象类语法

包含抽象方法的类,必须也拿abstract修饰 ,此时这个类也叫抽象类

abstract class Shape {// 抽象方法public abstract void draw();
}

9.1.3 抽象类的特性

  1. 抽象类不能被实例化
    在这里插入图片描述
  2. 如果一个普通类继承了一个抽象类,那么此时这个普通类 必须重写这个抽象方法
class Cycle extends Shape {// 一定要重写父类的这个抽象方法@Overridepublic void draw() {System.out.println("⚪");}
}
  1. 在一个普通类继承了抽象类,如果再被继承,那这个普通类必须同时重写这两个类
abstract class A extends Shape {public abstract void testA();}class B extends A {@Overridepublic void testA() {}@Overridepublic void draw() {}
}
  1. 抽象类和 普通类 的区别在于:
  • 可以和普通类一样 有成员变量、成员方法
  • 多了抽象方法
  • 多了不能实例化
  1. 什么情况下 要设计为抽象类
    如果这个类 不能描述一个而具体的对象,那么就可以设置为抽象类
    比如:Animal这个类

  2. 抽象类当中可以包含构造方法,这个构造方法并不是实例化这个抽象类的时候使用,因为他就不能被实例化。那么这个构造方法,主要是在子类当中让子类调用,帮助父类进行初始化

abstract class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}
}
class Student extends Person {public Student() {super("zhangsan", 10);}
}
  1. 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类

9.1.4 抽象类的作用

抽象类本身不能被实例化,要想使用,只能创建该抽象类的子类,然后让子类重写抽象类中的抽象方法。
使用抽象类相当于多了一重编译器的校验。
使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题。

9.2 接口

9.2.1 接口的概念

在现实生活里,接口的例子比如有:笔记本上的USB口,电源插座等。
而USB口可以插 U盘、鼠标、键盘等所有符合USB协议的设备。
接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型

9.2.2 语法规则

  1. 定义一个接口的时候使用关键字interface来定义

提示:

  1. 创建接口时, 接口的命名一般以大写字母 I 开头.
  2. 接口的命名一般使用 “形容词” 词性的单词.
  3. 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性.

9.2.3 接口使用

接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法

IUSB接口:

public interface IUSB {void openDevice();void closeDevice();
}

Mouse类:

public class Mouse implements IUSB{@Overridepublic void openDevice() {System.out.println("打开鼠标");}public void click() {System.out.println("点击鼠标");}@Overridepublic void closeDevice() {System.out.println("关闭鼠标");}
}

Keyboard类:

public class KeyBoard implements IUSB{@Overridepublic void openDevice() {System.out.println("打开键盘");}public void inPut() {System.out.println("键盘输入");}@Overridepublic void closeDevice() {System.out.println("关闭键盘");}
}

Computer类:

public class Computer {public void powerOn() {System.out.println("打开电脑");}public void powerOff() {System.out.println("关闭电脑");}public void useDevice(IUSB iusb) {iusb.openDevice();// instanceof :测试它左边的对象是否是它右边的类的实例 ,返回boolean类型// A(对象) instanceof B(类)if (iusb instanceof Mouse) {Mouse mouse = (Mouse) iusb;mouse.click();}else if(iusb instanceof KeyBoard) {KeyBoard keyBoard = (KeyBoard) iusb;keyBoard.inPut();}iusb.closeDevice();}
}

Test类:

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();}
}

在这里插入图片描述

9.2.4 接口特性

  1. 接口当中的方法 如果没有被实现, 那么他默认就是一个抽象方法
  2. 在接口当中的方法不能有具体的实现
  3. 如果有具体的实现,那么必须是由default修饰或者是static修饰
interface Ishape {public int a = 10;public abstract void draw();//在接口当中的方法不能有具体的实现//如果有具体的实现,那么必须是由default修饰或者是static修饰public default void test() {System.out.println("ds");}public static void func() {}
}
  1. 接口当中定义成员变量 默认都是public static final的
    public int a = 10;public static final int b = 100;int aa = 10; // 可以不加public static final 直接定义int aa = 10;int bb = 20;
  1. 接口当中的抽象方法 默认都是public abstract修饰的
    public abstract void draw();void fun1();
  1. 接口类型是一种引用类型,是不可以被实例化
    在这里插入图片描述
  2. 类和接口之间的关系 可以使用implements来关联
interface IShape {void draw();
}class Rect implements IShape{@Overridepublic void draw() {System.out.println("矩形");}
}class Cycle implements IShape {@Overridepublic void draw() {System.out.println("⚪");}
}class Flower implements IShape {@Overridepublic void draw() {System.out.println("❀");}
}public class Test {public static void func(IShape iShape) {iShape.draw();}public static void main(String[] args) {//IShape iShape = new IShape();IShape iShape1 = new Flower();IShape iShape2 = new Rect();IShape iShape3 = new Cycle();func(iShape1);func(iShape2);func(iShape3);IShape[] iShapes = {iShape1,iShape2,iShape3};}
}
  1. 接口也是可以产生字节码文件的(.class)
  2. 接口中不能有静态代码块和构造方法
public interface USB {// 编译失败public USB(){}{} // 编译失败void openDevice();void closeDevice();
}
  1. 一个类 可以继承一个抽象类/普通类 同时还可以实现这个接口
abstract class AA {}
class CC extends AA implements IUSB {}

9.2.5 实现多个接口

在Java中,类和类之间是单继承的,一个类只能有一个父类,即Java中不支持多继承,但是一个类可以实现多个接口。下面通过类来表示一组动物.

public abstract class Animal {public String name;public Animal(String name) {this.name = name;}public abstract void eat();
}

提供一组接口,分别表示会飞,会跑,会游泳
会飞的接口:

public interface IFly {void fly();
}

会跑的接口:

public interface IRun {void run();
}

会游泳的接口:

public interface ISwim {void swim();
}

创建鸟,狗,鸭子,机器人这个类:

鸟:

public class Bird extends Animal implements IFly,IRun{public Bird(String name) {super(name);}@Overridepublic void fly() {System.out.println(this.name+" 正在用两个翅膀飞");}@Overridepublic void eat() {System.out.println(this.name + "正在吃鸟粮");}@Overridepublic void run() {System.out.println(this.name+ " 正在用两个小腿跑");}
}

狗:

public class Dog extends Animal implements ISwim,IRun{public Dog(String name) {super(name);}@Overridepublic void swim() {System.out.println(this.name+" 正在用4条腿游泳");}@Overridepublic void eat() {System.out.println(this.name+ " 正在吃狗粮");}@Overridepublic void run() {System.out.println(this.name+" 正在用4条腿跑");}
}

鸭子:

public class Duck extends Animal implements IFly,IRun,ISwim{public Duck(String name) {super(name);}@Overridepublic void eat() {System.out.println(this.name+" 正在吃鸭粮");}@Overridepublic void fly() {System.out.println(this.name+" 正在用鸭翅膀飞");}@Overridepublic void run() {System.out.println(this.name+"正在用鸭腿跑");}@Overridepublic void swim() {System.out.println(this.name+"正在用鸭腿游泳");}
}

机器人:

public class Robot implements IRun{@Overridepublic void run() {System.out.println("机器人在跑");}
}

Test类:

public class Test {public static void func1(Animal animal) {animal.eat();}public static void testFly(IFly iFly) {iFly.fly();}public static void testSwim(ISwim iSwim) {iSwim.swim();}public static void testRun(IRun iRun) {iRun.run();}public static void main(String[] args) {func1(new Duck("小黄鸭"));testFly(new Duck("小黄鸭"));testSwim(new Duck("小黄鸭"));testFly(new Bird("布谷"));func1(new Dog("旺财"));// testFly(new Dog("旺财"));  // 报错 狗没有Ifly接口testRun(new Robot());}
}

在这里插入图片描述

注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类。一个类继承一个父类,同时实现多种接口。

9.2.6 接口的继承

在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。即:用接口可以达到多继承的目的。
接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字.

// 两栖的动物, 既能跑, 也能游
public interface IAmphibious extends IRun,ISwim {void test1();
}

再创建一个Frog类接口实现run方法和swim方法:

public class Frog extends Animal implements IAmphibious{public Frog(String name) {super(name);}@Overridepublic void eat() {}@Overridepublic void test1() {}@Overridepublic void run() {}@Overridepublic void swim() {}
}

接口间的继承相当于把多个接口合并在一起

9.2.9 抽象类和接口的区别

  1. 抽象类当中,可以包含和普通类一样的成员变量和成员方法,但是接口当中的成员变量只能是public static final的,方法只能是public abstract
  2. ** 一个类只能继承一个抽象类,但是能够同时实现多个接口**,所以解决了Java当中不能进行多继承的特性

9.3 Object类

Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父类。即所有类的对象都可以使用Object的引用进行接收。
Object是所以类的父类,意味着可以发生向上转型,能接受所以类的对象。

class Person {public String name;
}class Student extends Person {}
public class Test {public static void main(String[] args) {Person person = new Person();//Object 是所以类的父类,意味着可以发生向上转型Object obj = new Person();Object obj1 = new Student();}
}

9.3.1 获取对象方法

如果要打印对象中的内容,可以直接重写Object类中的toString()方法、
在这里插入图片描述

class Person {public String name = "haha";@Overridepublic String toString() {return "name: "+ name;}
}class Student extends Person {}
public class Test {public static void main(String[] args) {Person person = new Person();System.out.println(person);//Object 是所以类的父类,意味着可以发生向上转型/*Object obj = new Person();Object obj1 = new Student();*/}
}

9.3.1 对象比较equals方法

在Java中,进行比较时:
a.如果
左右两侧是基本类型变量,比较的是变量中值是否相同
b.如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同
c.如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的:

// Object类中的equals方法
public boolean equals(Object obj) {return (this == obj); // 使用引用中的地址直接来进行比较
}
class Person {public String name;public Person(String name){this.name = name;}@Overridepublic String toString() {return "name: "+ name;}@Overridepublic boolean equals(Object obj) {//发生动态绑定Person tmp = (Person) obj;return tmp.name.equals(this.name);}
}public class Test {public static void main(String[] args) {Person person1 = new Person("zhangsan");Person person2 = new Person("zhangsan");System.out.println(person1 == person2);//调用了object方法,所以要在Person类重写equals方法System.out.println(person1.equals(person2));String str1 = "zhangsan";String str2 = "zhangsan";System.out.println(str1.equals(str2));}
}

比较对象中内容是否相同的时候,一定要重写equals方法。

9.3.2 hashcode方法

重写hashCode之后哈希值就会相同
在这里插入图片描述

import java.util.Objects;class Person {public String name;public Person(String name){this.name = name;}@Overridepublic String toString() {return "name: "+ name;}/*@Overridepublic boolean equals(Object obj) {//发生动态绑定Person tmp = (Person) obj;return tmp.name.equals(this.name);}*/@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name);}
}public class Test {public static void main(String[] args) {Person person1 = new Person("zhangsan");Person person2 = new Person("zhangsan");System.out.println(person1.hashCode());System.out.println(person2.hashCode());System.out.println(person1.equals(person2));}

注意:

  1. hashcode方法用来确定对象在内存中存储的位置是否相同
  2. 事实上hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。

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

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

相关文章

centos中安装的goland配置sdk报错:所选的目录不是Go SDK的有效主路经

选中目录后一直报错: 正确的位置: 原因竟然是使用 解压go1.21.4.linux-amd64.tar.gz 包出来,少了scr和test目录,重新解压后可以正确设定SDK主目录。 有同样问题的可以确认一下。 tar -C /usr/local -zxvf go1.19.2.linux-amd64.…

改进YOLO系列 | YOLOv5/v7 引入Super Token Sampling ViT | 《CVPR 2023 最新论文》

论文地址:https://arxiv.org/abs/2211.11167 代码地址:https://github.com/hhb072/STViT 视觉变换器已经在许多视觉任务中取得了令人印象深刻的性能。然而,它在捕捉浅层的局部特征时可能会受到高度冗余的影响。因此,引入了局部自注意力或早期卷积,这些方法牺牲了捕捉长距…

刚柔相济铸伟业 ——访湖南顺新金属制品科技有限公司董事长张顺新

时代在变,唯初心不改。 精致、谦虚、谨慎、儒雅、温和——他就是张顺新,湖南顺新金属制品科技有限公司、湖南顺新供应链管理有限公司董事长,民建长沙市委常委,民建湖南省环资委副主任,省、市民建企联会常务副会长&…

CentOS7、CentOS8 如何修改ip信息(修改网络信息)(无图形界面)(亲测可用)

文章目录 CentOS 7方法一:使用 nmcli 命令方法二:编辑配置文件(我的CentOS7是使用这种方法,亲测可用) CentOS 8方法一:使用 nmcli 命令方法二:编辑配置文件 在 CentOS 系统中,如果你…

加班把数据库重构完毕

加班把数据库重构完毕 本文的数据库重构是基于 clickhouse 时序非关系型的数据库。该数据库适合存储股票数据,速度快,一般查询都是 ms 级别,不需要异步查询更新界面 ui。 达到目标效果:数据表随便删除,重新拉数据以及指…

Yolo自制detect训练

Install 把代码拉下来 GitHub - ultralytics/yolov5 at v5.0 然后 pip install -r requirements.txt 安装完了,运行一下detect.py即可 结果会保存在对应的目录下 Intro ├── data:主要是存放一些超参数的配置文件(这些文件(yaml文件)是用来配置训练集和测试集还有验…

Maven内网开发使用离线仓库

Maven内网开发使用离线仓库 离线或者内网环境开发与外网不通,中央仓库连不上,使用 Maven 管理项目会遇到很多问题。 比如:依赖包缺失,内网的Nexus私服的包老旧,很久没有维护,项目无法运行打包,…

力扣字符串--总结篇

前言 字符串学了三天,七道题。初窥kmp,已经感受到算法的博大精深了。 内容 对字符串的操作可以归结为以下几类: 字符串的比较、连接操作(不同编程语言实现方式有所不同); 涉及子串的操作,比…

10-Docker-分布式存储算法

01-哈希取余算法分区 哈希取余分区(Hash Modulus Partitioning)是一种在分布式计算和数据存储中常用的分区策略,其目的是将数据或计算任务分配到多个节点或服务器上,以实现负载均衡和提高性能。这种分区策略的核心思想是使用哈希…

【C语言】【数据结构】【环形链表判断是否带环并返回进环节点】有数学推导加图解

1.判断是否带环: 用快慢指针 slow指针一次走一步,fast指针一次走两步 当两个指针相遇时,链表带环;两个指针不能相遇时,当fast走到倒数第一个节点或为空时,跳出循环返回空指针。 那么slow指针一次走一步&a…

Python进行多线程爬取数据通用模板

首先,我们需要导入所需的库,包括requests和BeautifulSoup。requests库用于发送HTTP请求,BeautifulSoup库用于解析HTML文档。 import requests from bs4 import BeautifulSoup然后,我们需要定义一个函数来发送HTTP请求并返回响应。…

Spring Security使用总结五,加密用户密码,不再使用明文保存密码

上一章我们成功的注册了一个新用户,按照正常逻辑来说,这一章应该是登录了,但是我们也看到了,这数据库保存的居然是明文密码,这谁受得了,这要是用户信息泄露了,这不让人一锅端了啊,还…