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

news2024/11/17 1:36:49

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 {
    // 一定要重写父类的这个抽象方法
    @Override
    public void draw() {
        System.out.println("⚪");
    }
}
  1. 在一个普通类继承了抽象类,如果再被继承,那这个普通类必须同时重写这两个类
abstract class A extends Shape {
    public abstract void testA();

}

class B extends A {
    @Override
    public void testA() {
    
    }

    @Override
    public 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{
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }

    public void click() {
        System.out.println("点击鼠标");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }
}

Keyboard类:

public class KeyBoard implements IUSB{
    @Override
    public void openDevice() {
        System.out.println("打开键盘");
    }

    public void inPut() {
        System.out.println("键盘输入");
    }
    @Override
    public 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{
    @Override
    public void draw() {
        System.out.println("矩形");
    }
}

class Cycle implements IShape {
    @Override
    public void draw() {
        System.out.println("⚪");
    }
}

class Flower implements IShape {
    @Override
    public 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);
    }

    @Override
    public void fly() {
        System.out.println(this.name+" 正在用两个翅膀飞");
    }

    @Override
    public void eat() {
        System.out.println(this.name + "正在吃鸟粮");
    }

    @Override
    public void run() {
        System.out.println(this.name+ " 正在用两个小腿跑");
    }
}

狗:

public class Dog extends Animal implements ISwim,IRun{
    public Dog(String name) {
        super(name);
    }

    @Override
    public void swim() {
        System.out.println(this.name+" 正在用4条腿游泳");
    }

    @Override
    public void eat() {
        System.out.println(this.name+ " 正在吃狗粮");
    }

    @Override
    public void run() {
        System.out.println(this.name+" 正在用4条腿跑");
    }
}

鸭子:

public class Duck extends Animal implements IFly,IRun,ISwim{

    public Duck(String name) {
        super(name);
    }

    @Override
    public void eat() {
        System.out.println(this.name+" 正在吃鸭粮");
    }

    @Override
    public void fly() {
        System.out.println(this.name+" 正在用鸭翅膀飞");
    }

    @Override
    public void run() {
        System.out.println(this.name+"正在用鸭腿跑");
    }

    @Override
    public void swim() {
        System.out.println(this.name+"正在用鸭腿游泳");
    }
}

机器人:

public class Robot implements IRun{
    @Override
    public 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);
    }
    @Override
    public void eat() {

    }
    @Override
    public void test1() {

    }
    @Override
    public void run() {

    }
    @Override
    public 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";

    @Override
    public 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;
    }

    @Override
    public String toString() {
        return "name: "+ name;
    }

    @Override
    public 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;
    }

    @Override
    public String toString() {
        return "name: "+ name;
    }

    /*@Override
    public boolean equals(Object obj) {
        //发生动态绑定
        Person tmp = (Person) obj;
        return tmp.name.equals(this.name);
    }*/

    @Override
    public 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);
    }

    @Override
    public 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.coloradmin.cn/o/1200784.html

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

相关文章

【论文精读】DMVSNet

今天读的是一篇发表在ICCV 2023上的文章,作者来自华中科技大学。 文章地址:点击前往 项目地址:Github 文章目录 Abstract1 Introduction2 Relative Work3 Motivation3.1 Estimated bias and interpolated bias3.2 One-sided V.S. Saddle-shap…

Leetcode154. Find Minimum in Rotated Sorted Array II

旋转数组找最小,这次值可以重复 不妨假设你已经做了上一题,题解 上一题的方法1肯定是用不了了,因为不再能完全分成2个不同的部分 所以我们沿着方法2走 如果 > n u m s [ r ] >nums[r] >nums[r],我们依然可以找右半边 …

SpringBoot 自动配置原理

SpringBoot 自动配置原理 注: 本文使用的springboot版本为 2.7.11 1、SpringBootApplication 字面分析,这个注解是标注一个Spring Boot应用。 Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Documented Inherited SpringBootConfiguration En…

电路设计之36V 自动断电和防浪涌电路

1. 电路图纸 2. 解释防浪涌功能怎么实现的 1. 首先当电源上电的一瞬间是 电容C1 是相当于短路的。 (电容的充电状态。电容充电相当于短路状态) 2. 当上电的一瞬间是有 浪涌的。 3.当上电的瞬间有浪涌的,此时电容C1 相当于短路,所…

第一百七十一回 SearchBar组件

文章目录 1. 概念介绍2. 使用方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"Material3中的IconButton"相关的内容,本章回中将 介绍SearchBar组件.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

自定义类型:联合和枚举

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1. 联合体 1.1 联合体类型的声明 1.2 联合体的特点 1.3 相同成员的结构体和联合体对比 1.4 联合体大小的计算 1.5 联合的一个练习 2. 枚举类型 2.1 枚举类型的声明…

MSF图形化工具Viper快速安装

简介 Viper(炫彩蛇)是一款图形化内网渗透工具,将内网渗透过程中常用的战术及技术进行模块化及武器化. Viper(炫彩蛇)集成杀软绕过,内网隧道,文件管理,命令行等基础功能. Viper(炫彩蛇)当前已集成70个模块,覆盖初始访问/持久化/权限提升/防御绕过/凭证访问/信息收集/横向移动等…

链表OJ题(4)

目录 10.链表的回文结构 11.随机链表的复制 🙂找中间节点一定要考虑偶数个和奇数个的问题。 🙂指针指向的前中后。 🙂链表节点的位置个数/链表的节点中的数字。🆗🆗 今天最后两道链表OJ题目。 10.链表的回文结构…

事件循环Eventloop

事件循环 浏览器的进程模型 何为进程? 程序运行需要有它自己专属的内存空间,可以把这块内存空间简单的理解为进程 每个应用至少有一个进程,进程之间相互独立,即使要通信,也需要双方同意。 何为线程? 有…

AIGC专栏8——EasyPhoto 视频领域拓展-让AIGC肖像动起来

AIGC专栏8——EasyPhoto 视频领域初拓展-让AIGC肖像动起来 学习前言源码下载地址技术原理储备Video Inference 功能说明 & 效果展示1、Text2Video功能说明a、实现原理简介b、文到视频UI介绍c、结果展示 2、Image2Video功能说明a、实现原理简介i、单图模式ii、首尾图模式 b、…

KDE Plasma 6 将不支持较旧的桌面小部件

KDE Plasma 6 进行了一些修改,需要小部件作者进行调整。开发人员,移植时间到了! KDE Plasma 6 是备受期待的桌面环境版本升级版本。 最近,其发布时间表公布,第一个 Alpha 版本将于 2023 年 11 月 8 日上线&#xff0…

Vue3+NodeJS 接入文心一言, 发布一个 VSCode 大模型问答插件

目录 一&#xff1a;首先明确插件开发方式 二&#xff1a;新建一个Vscode 插件项目 1. 官网教程地址 2. 一步一步来创建 3. 分析目录结构以及运行插件 三&#xff1a;新建一个Vue3 项目&#xff0c;在侧边栏中展示&#xff0c;实现vscode插件 <> vue项目 双向消息传…

Nuxt.js——基于 Vue 的服务端渲染应用框架

文章目录 前言一、知识普及什么是服务端渲染什么是客户端渲染&#xff1f;服务端渲染与客户端渲染那个更优秀&#xff1f; 二、Nuxt.js的特点Nuxt.js的适用情况&#xff1f; 三、Vue是如何实现服务端渲染的&#xff1f;安装依赖使用vue安装 Nuxt使用npm install安装依赖包使用n…

配置云服务器

一、概念 现如今越来越多的企业或者个人开发者都会选择去购买一台云服务器&#xff0c;云服务器相比较与传统的物理服务器他的价格优势&#xff0c;以及一系列可客制化的服务也方便大家去选择&#xff0c;大大节约了空间&#xff0c;运维&#xff0c;开发等等一系列成本。现如…

Python---字符串 lstrip()--删除字符串两边的空白字符、rstrip()--删除字符串左边的空白字符、strip()--删除字符串右边的空白字符

strip() 方法主要作用&#xff1a;删除字符串两边的空白字符&#xff08;如空格&#xff09; lstrip() 方法 left strip&#xff0c;作用&#xff1a;只删除字符串左边的空白字符 left 英 /left/ 左 rstrip() 方法 right strip&#xff0c;作用&#xff1a;只删除字符…

ELK之Logstash解析时间相差8h的问题

一、问题描述 服务器当前时间为&#xff1a;2022年 06月 28日 星期二 11:24:22 CST 而logstash解析的时间为2022-06-28T03:15:25.545Z与实际时间相差8h 一、解决办法&#xff1a; 需改logstash的配置文件&#xff1a; 原理就是&#xff1a;定义一个中间变量timestamp&…

【Java 进阶篇】Java与JQuery:探秘事件绑定、入口函数与样式控制

在现代的Web开发中&#xff0c;Java和JQuery是两个不可或缺的角色。Java为我们提供了强大的后端支持&#xff0c;而JQuery则是前端开发的得力助手。本篇博客将围绕Java和JQuery&#xff0c;深入探讨事件绑定、入口函数和样式控制&#xff0c;带你进入前端开发的奇妙世界。 Jav…

小程序中如何设置门店信息

小程序是商家转型升级的利器&#xff0c;小程序中门店信息的准确性和完整性对于用户的体验和信任度都有很大的影响。下面具体介绍门店信息怎么在小程序中进行设置。 在小程序管理员后台->门店设置处&#xff0c;可以门店设置相关。主要分为2个模块&#xff0c;一个是门店级…

基于springboot实现驾校管理系统项目【项目源码】计算机毕业设计

基于springboot实现驾校管理系统演示 JAVA简介 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&#xff0…

数据结构与算法—归并排序计数排序

目录 一、归并排序 1、主函数 2、递归实现 3、优化递归 4、非递归实现 5、特性总结&#xff1a; 二、计数排序 1、代码&#xff1a; 2、特性总结&#xff1a; 三、各种排序稳定性总结 一、归并排序 基本思想&#xff1a; 归并排序是建立在归并操作上的一种有效的排序…