【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 {
    // 一定要重写父类的这个抽象方法
    @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() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

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

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

小H靶场学习笔记:DC-2

DC-2 Created: November 10, 2023 3:01 PM Tags: WordPress, git提权, rbash逃逸 Owner: 只会摸鱼 靶场过程 信息收集 扫描存活主机,找到靶机ip:192.168.199.131(本机是192.168.199.129) 扫描端口开放协议 发现有80端口和77…

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

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

Java学习_对象

对象在计算机中的执行原理 类和对象的一些注意事项 this关键字 构造器 构造器是一种特殊的方法 : 特殊之处在于,名字必须与所在类的名字一样,而且不能写返回值类型 封装 封装的设计规范:合理隐藏、合理暴露 实体类 成员变量和局部变量的区别 …

有源RS低通滤波

常用的滤波电路有无源滤波和有源滤波两大类。若滤波电路元件仅由无源元件(电阻、电容、电感)组成,则称为无源滤波电路。无源滤波的主要形式有电容滤波、电感滤波和复式滤波(包括倒L型、LC滤波、LCπ型滤波和RCπ型滤波等)。若滤波电路不仅有无…

【Redis】list列表

上一篇: String 类型 https://blog.csdn.net/m0_67930426/article/details/134362606?spm1001.2014.3001.5501 目录 Lpush LRange Rpush Lpop Rpop Lindex Ltrim Lset 列表不存在的情况 如果列表存在 Linsert ​编辑 在………之前插入 在……后面插入…

UE地形系统材质混合实现和Shader生成分析(UE5 5.2)

前言 随着电脑和手机硬件性能越来越高,游戏越来越追求大世界,而大世界非常核心的一环是地形系统,地形系统两大构成因素:高度和多材质混合,此篇文章介绍下UE4/UE5 地形的材质混合方案----基于WeightMap混合。 材质层 …

总结:利用JDK原生命令,制作可执行jar包与依赖jar包

总结:利用JDK原生命令,制作可执行jar包与依赖jar包 一什么是jar包?二制作jar包的工具:JDK原生自带的jar命令(1)jar命令注意事项:(2)jar包清单文件创建示例:&a…

Yolo自制detect训练

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

【Redis】set 集合

上一篇:list 列表 https://blog.csdn.net/m0_67930426/article/details/134364315?spm1001.2014.3001.5501 目录 Sadd Smembers Sismember Scard Srem ​编辑Srandomember Spop Smove 集合类 Sdiff Sinter Sunion 官网 https://redis.io/commands/?…

01-Spring中的工厂模式

工厂模式 工厂模式的三种形态: 工厂模式是解决对象创建问题的属于创建型设计模式,Spring框架底层使用了大量的工厂模式 第一种:简单工厂模式是工厂方法模式的一种特殊实现,简单工厂模式又叫静态工厂方法模式不属于23种设计模式之一第二种:工厂方法模式…

记录一次某某虚拟机的逆向

导语 学了一段时间的XPosed,发现XPosed真的好强,只要技术强,什么操作都能实现... 这次主要记录一下我对这款应用的逆向思路 apk检查 使用MT管理器检查apk的加壳情况 发现是某数字的免费版本 直接使用frida-dexdump 脱下来后备用 应用分…

基于springboot实现桥牌计分管理系统项目【项目源码】

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

Lambertian模型(完美漫反射)

这里使用相乘的方式组合光照色和纹理色。根据这个模型,面朝光源的区域光照强度高,纹理色也相应增强。面背光源的区域光照弱,纹理色也被抑制。这样通过光照和纹理的结合,可以合成出具有照明效果的面部颜色,而不仅仅是固定的纹理本身的颜色。相乘方式可以近似实现不同光照方向下面…

“第六十六天”

这个我记得是有更优解的&#xff0c;不过还是明天发吧&#xff0c;明天想一想&#xff0c;看看能不能想起来 #include<string.h> int main() {char a[201] { 0 };char b[201] { 0 };scanf("%s %s", a, b);int na strlen(a);int nb strlen(b);int i 0, j …

Leetcode421. 数组中两个数的最大异或值

Every day a Leetcode 题目来源&#xff1a;421. 数组中两个数的最大异或值 解法1&#xff1a;贪心 位运算 初始化答案 ans 0。从最高位 high_bit 开始枚举 i&#xff0c;也就是 max⁡(nums) 的二进制长度减一。设 newAns ans 2i&#xff0c;看能否从数组 nums 中选两个…

基于SpringBoot+Vue的在线学习平台系统

基于SpringBootVue的在线学习平台系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 用户界面 登录界面 管理员界面 摘要 本文设计并实现了一套基于Spri…

【MySQL】使用C/C++访问MySQL

文章目录 一. 环境准备1. 方法一2. 方法二 二. MySQL接口介绍1. 初始化/连接/关闭2. 执行操作3. 查找操作 结束语 本篇环境是云服务器Centos上的MySQL 版本; 一. 环境准备 使用C/C访问MySQL&#xff0c;首先需要MySQL的开发者库 这里提供两种方法&#xff1a; 1. 方法一 …

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

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

音视频基础知识

图像&#xff08;YUV RGB&#xff09; ​​​​​​​​​​​​​​这个讲的比较好 RGB颜色编码 图像显示主要是由像素组成&#xff0c;每个像素点的颜色组成都是采用RGB格式&#xff0c;RGB就是红、绿、蓝&#xff0c;RGB分别取不同的值&#xff0c;展示不同的颜色。 YUV…