Day10-面向对象-抽象类和接口

news2024/9/21 20:52:43

文章目录

    • 学习目标
    • 1. 抽象类
      • 1.1 抽象类注意事项
      • 1.2 修饰符的使用
    • 2. 接口
      • 2.1 定义接口
      • 2.2 接口里可以定义的成员
      • 2.2 实现接口
        • 2.2.1 实现接口语法格式
        • 2.2.2 如何调用对应的方法
        • 2.2.3 练习
      • 2.3 接口的多实现
        • 2.3.1 练习
      • 2.4 冲突问题
      • 2.5 接口的多继承(了解)
      • 2.6 部分内置接口

学习目标

  • 能够声明抽象类
  • 能够说出抽象类的特点
  • 能够继承抽象类
  • 掌握声明接口的格式
  • 掌握实现接口的格式
  • 能够说出接口中的特点
  • 系统内置接口

1. 抽象类

父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。既然被子类重写了,那么父类里的方法,就只有声明还有意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类

抽象类存在的意义:抽象类往往用来表示对问题领域进行分析、设计中得出的抽象概念。其存在的意义在于其设计性、复用性与扩展性,仅仅是对功能的声明,表示该类有这个功能,但是具体的功能需要由子类来实现。说白了,抽象类就是用来继承和重写的。

Java中使用关键字abstract来声明抽象方法和抽象类。

abstract class 类名字 { 
	public abstract void 方法名(); 
}

1.1 抽象类注意事项

  1. 一个抽象类里可以有抽象方法,也可以没有抽象方法,不建议抽象类里不定义任何抽象方法的行为。

    abstract class Test {
        public void test(){}
    }
    // 抽象类里可以全都是具体方法,没有抽象方法(不建议使用)
    
  2. 如果一个类里有了抽象方法,那么这个类必须要声明为抽象类。

    abstract class Test{
        public abstract void demo();  // 只要有了抽象方法,那么这个类必须要抽象
    }
    
  3. 抽象类不能直接创建对象,如果一定要创建,需要实现(重写)抽象方法。

    class Test {
        public static void main(String []args) {
            // Animal animal = new Animal(); 报错,抽象类不能直接创建对象
            
            // 如果要创建对象,必须要实现抽象类里的所有抽象方法
            Animal animal = new Animal(){   
                public void shout(){
                    System.out.println("动物正在叫");
                }
            };
        }
    }
    abstract class Animal{
        public abstract void shout();
    }
    
  4. 通常情况下,我们会创建一个继承抽象类的子类,在子类里实现所有的抽象方法,然后去创建子类对象。

    public class Test {
        public static void main(String[] args) {
            Dog d = new Dog();
        }
    }
    abstract class Animal {
        public abstract void shout();
        public abstract void eat();
    }
    class Dog extends Animal {
        @Override
        public void shout() {
            System.out.println("小狗正在汪汪汪");
        }
        @Override
        public void eat() {
            System.out.println("小狗正在啃骨头");
        }
    }
    
  5. 如果子类没有实现父类所有的抽象方法,那么这个子类也需要被定义成为抽象的。

    abstract class Animal {
        public abstract void shout();
        public abstract void eat();
    }
    abstract class Dog extends Animal {
        @Override
        public void shout() {
            System.out.println("小狗正在汪汪汪");
        }
    }
    

子类对父类抽象方法的重写操作也叫做实现方法

1.2 修饰符的使用

外部类成员变量代码块构造器方法局部变量内部类(后面讲)
public××
protected×××
缺省
private×××
static×××
final××
abstract××××
native××××××

不能和abstract一起使用的修饰符?

(1)abstract和final不能一起修饰方法和类

(2)abstract和static不能一起修饰方法

(3)abstract和native不能一起修饰方法

(4)abstract和private不能一起修饰方法

static和final一起使用:

(1)修饰方法:可以,因为都不能被重写

(2)修饰成员变量:可以,表示静态常量

(3)修饰局部变量:不可以,static不能修饰局部变量

(4)修饰代码块:不可以,final不能修改代码块

(5)修饰内部类:可以一起修饰成员内部类,不能一起修饰局部内部类

2. 接口

  • 一方面,有时必须从几个类中派生出一个子类,继承它们所有的方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
  • 另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都支持USB连接。
  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。继承是一个"是不是"的关系,而接口实现则是 "能不能"的关系。has-a
    • 例如:你想要会飞,那么必须拥有fly()方法
    • 例如:你想要连接USB,那么必须拥有read()/in()和write()/out()等
    • 例如:你的数据库产品想要被Java连接,那么你需要实现Connection, Statement等
  • 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。

在这里插入图片描述

2.1 定义接口

接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(JDK 9)。

接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。

引用数据类型:数组,类,接口。

接口的声明格式:

[修饰符】 interface 接口名{
    //接口的成员列表:
    // 静态常量
    // 抽象方法
    // 默认方法
    // 静态方法
    // 私有方法
}

示例代码:

interface Flyable{
    //静态常量
	long MAX_SPEED = 7900000;//这里单位是毫米/秒,7.9千米/秒,超过这个速度,就变成卫星
    //抽象方法
	void fly();   
    //默认方法
    public default void start(){
        System.out.println("开始");
    }
    public default void stop(){
        System.out.println("结束");
    }
    //静态方法
    public static void broken(){
        System.out.println("飞行中遇到物体就坏了");
    }
}

在JDK8之前,接口中只运行出现:

(1)公共的静态的常量:其中public static final可以省略。

(2)公共的抽象的方法:其中public abstract可以省略。

在JDK1.8时,接口中允许声明默认方法和静态方法:

(3)公共的默认的方法:其中public 可以省略,建议保留。

默认方法相当于允许给接口的抽象方法给出默认实现了,这样实现类(子类)既可以选择使用默认实现,还可以选择重写,更灵活了

(4)公共的静态的方法:其中public 可以省略,建议保留。

2.2 接口里可以定义的成员

接口里只能定义以下几种成员:

  1. 静态成员常量。接口里定义的变量默认被 public static final 修饰
  2. 抽象方法。接口里定义的方法默认被 public abstract修饰,不能有方法体
  3. 默认方法。JDK8以后,接口里可以使用 public default 定义有方法体的默认方法。
  4. 静态方法。JDK8以后,接口里还可以使用 public static 定义静态方法
  5. 私有方法。JDK9以后,接口里可以使用private定义私有方法。

注意:接口里不能定义构造方法!

2.2 实现接口

接口不能直接创建实例对象,需要定义一个子类实现(继承)这个接口,然后再创建子类对象。

类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements关键字。

2.2.1 实现接口语法格式
[修饰符】 class 实现类  implements 接口{
	// 重写接口中抽象方法[必须】,当然如果实现类是抽象类,那么可以不重写
  	// 重写接口中默认方法[可选】
}
[修饰符】 class 实现类 extends 父类 implements 接口{
    // 重写接口中抽象方法[必须】,当然如果实现类是抽象类,那么可以不重写
  	// 重写接口中默认方法[可选】
}

非抽象子类实现接口:

  1. 必须重写接口中所有抽象方法。

  2. 继承了接口的默认方法,即可以直接调用,也可以重写。

    重写时,default单词就不要再写了,它只用于在接口中表示默认方法,到类中就没有默认方法的概念了

  3. 不能重写静态方法

示例代码:

class Bird implements Flyable{

	//重写/实现接口的抽象方法,[必选】
	public void fly() {
		System.out.println("展翅高飞");
	}
	
	//重写接口的默认方法,[可选】
	//重写默认方法时,default单词去掉
	public void start(){
        System.out.println("先扇两下翅膀,一蹬腿,开始飞");
    }
}
2.2.2 如何调用对应的方法
  • 对于接口的抽象方法、默认方法,通过实现类对象就可以调用
  • 但是对于静态方法,必须使用接口名才能调用。
public class TestInteface {
	public static void main(String[] args) {
		//创建实现类对象
		Bird b = new Bird();
		
		//通过实现类对象调用重写的抽象方法,以及接口的默认方法,如果实现类重写了就执行重写的默认方法,如果没有重写,就执行接口中的默认方法
		b.start();
		b.fly();
		b.stop();
		
		//通过接口名调用接口的静态方法
		Flyable.broken();
	}
}
2.2.3 练习
  1. 声明一个Creature接口

    • 包含两个抽象方法:
      • void eat();
      • void breathe();
      • 包含默认方法 default void sleep(),实现为打印“静止不动”
      • 包含静态方法 static void drink(),实现为“喝水”
  2. 声明动物Animal类,实现Creature接口。

    • void eat();实现为“吃东西”,
    • void breathe();实现为"吸入氧气呼出二氧化碳"
    • void sleep()重写为”闭上眼睛睡觉"
  3. 声明植物Plant类,实现Creature接口。

    • void eat();实现为“吸收营养”
    • void breathe();实现为"吸入二氧化碳呼出氧气"
  4. 在测试类中,分别创建两个实现类的对象,调用对应的方法。通过接口名,调用静态方法。

定义接口:

public interface Creature {
    // 定义抽象方法
    public abstract void eat();
    public abstract void breathe();
    //定义默认方法
    public default void sleep(){
    	System.out.println("静止不动");
    }
    //定义静态方法
    public static void drink(){
    	System.out.println("喝水");
    }
}

定义实现类:

public Animal implements Creature {
	//重写/实现接口的抽象方法
    @Override
    public void eat() {
        System.out.println("吃东西");
    }
    
    //重写/实现接口的抽象方法
    @Override
    public void breathe(){
        System.out.println("吸入氧气呼出二氧化碳");
    }
    
    //重写接口的默认方法
    @Override
    public void sleep() {
        System.out.println("闭上眼睛睡觉");
    }
}
public class Plant implements Creature {
	//重写/实现接口的抽象方法
    @Override
    public void eat() {
        System.out.println("吸收营养");
    }
    //重写/实现接口的抽象方法
    @Override
    public void breathe(){
        System.out.println("吸入二氧化碳呼出氧气");
    }
}

定义测试类:

public class InterfaceDemo {
    public static void main(String[] args) {
        // 创建实现类(子类)对象  
        Animal a = new Animal();
        // 调用实现后的方法
        a.eat();
        a.sleep();
        a.breathe();
        
        //创建实现类(子类)对象
        Plant p = new Plant();
        p.eat();
        p.sleep();
        p.breathe();
        
        //通过接口调用静态方法
        Creature.drink();
    }
}
输出结果:
吃东西
闭上眼睛睡觉
吸入氧气呼出二氧化碳
吸收营养
静止不动
吸入二氧化碳呼出氧气
喝水

2.3 接口的多实现

之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。

实现格式:

[修饰符】 class 实现类  implements 接口1,接口2,接口3。。。{
	// 重写接口中所有抽象方法[必须】,当然如果实现类是抽象类,那么可以不重写
  	// 重写接口中默认方法[可选】
}

[修饰符】 class 实现类 extends 父类 implements 接口1,接口2,接口3。。。{
    // 重写接口中所有抽象方法[必须】,当然如果实现类是抽象类,那么可以不重写
  	// 重写接口中默认方法[可选】
}

接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次

定义多个接口:

interface A {
    public abstract void showA();
    public abstract void show();
}

interface B {
    public abstract void showB();
    public abstract void show();
}

定义实现类:

public class C implements A,B{
    @Override
    public void showA() {
        System.out.println("showA");
    }

    @Override
    public void showB() {
        System.out.println("showB");
    }

    @Override
    public void show() {
        System.out.println("show");
    }
}
2.3.1 练习
  1. 声明第一个接口Runner,包含抽象方法:void run()

  2. 声明第二个接口Swimming,包含抽象方法:void swim()

  3. 声明兔子类,实现Runner接口

  4. 声明乌龟类,实现Runner接口和Swimming接口

interface Runner{
	void run();
}
interface Swimming{
	void swim();
}
class Rabbit implements Runner{

	@Override
	public void run() {
		System.out.println("兔子跑得快");
	}
	
}
class Tortoise implements Runner,Swimming{

	@Override
	public void swim() {
		System.out.println("乌龟游得快");
	}

	@Override
	public void run() {
		System.out.println("乌龟跑的慢");
	}
	
}

2.4 冲突问题

当一个类可以继承一个父类,同时又能实现若干个接口。如果当继承和多实现的情况都同时存在时,调用方法时就需要确定到底调用那个方法。

下面的几个原则大家需要了解并记忆:

  • 自身优先:如果这个类自己实现或者重写了某个方法,优先调用自己的方法。

  • 父类优先:父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法。

    class A {
        public void test() {
            System.out.println("AAAAAA");
        }
        public void demo() {
            System.out.println("A类里的demo方法");
        }
    }
    
    interface B {
        public default void test() {
            System.out.println("BBBBBB");
        }
        public void demo() {
            System.out.println("B接口里的demo方法");
        }
    }
    
    interface C {
        public default void test() {
            System.out.println("CCCCCC");
        }
        public void demo() {
            System.out.println("C接口里的demo方法");
        }
    }
    
    class D extends A implements B, C {
        @Override
        public void test() {
            System.out.println("DDDDDD");
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            D d = new D();
            
            // 类自己重写了test方法,优先调用自己的方法。
            d.test();  // DDDDDD
            
            // 类没有重写demo方法,会优先调用父类里的实现
            d.demo();  // A类里的demo方法
        }
    }
    
  • 明确指定:在某些情况下,必须要自己手动实现或者明确的指定到底调用哪个接口的默认实现。

    interface A {
        public default void test() {
            System.out.println("BBBBB");
        }
    }
    
    interface B {
        public default void test() {
            System.out.println("CCCCCC");
        }
    }
    
    // 编译报错!因为此时类C实现的两个接口里,都有 test 方法,编译器不知道到底要调用哪个 test
    // class C implements A, B { }
    
    // 可以选择自己完全重写
    class D implements A,B {
        @Override
        public void test() {
            System.out.println("DDDDDD");
        }
    }
    
    class E implements A,B {
        @Override
        public void test() {
            A.super.test();  // 在重写的时候,也可以指定到底调用哪个接口的方法
        }
    }
    

2.5 接口的多继承(了解)

一个接口能继承另一个或者多个接口,接口的继承也使用 extends 关键字,子接口继承父接口的方法。

interface A {
    void a();
    public default void methodA(){
        System.out.println("AAAAAAAAAAAAAAAAAAA");
    }
}
interface B {
    void b();
    public default void methodB(){
        System.out.println("BBBBBBBBBBBBBBBBBBB");
    }
}

// 一个接口可以继承一个或者多个接口
interface C extends A,B{
    @Override
    public default void methodB() {
        System.out.println("CCCCCCCCCCCCCCCCCCCC");
    }
}

2.6 部分内置接口

  • Cloneable接口
  • Comparable接口
  • Comparator接口

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

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

相关文章

2024转行要趁早!盘点网络安全的岗位汇总

前段时间,知名机构麦可思研究院发布了《2024年中国本科生就业报告》,其中详细列出近五年的本科绿牌专业,信息安全位列第一。 对于网络安全的发展与就业前景,知了姐说过很多,作为当下应届生收入较高的专业之一&#xf…

【Python笔记-设计模式】对象池模式

一、说明 用于管理对象的生命周期,重用已经创建的对象,从而减少资源消耗和创建对象的开销 (一) 解决问题 主要解决频繁创建和销毁对象所带来的性能开销问题。如数据库连接、线程管理、网络连接等,对象的创建和销毁成本相对较高&#xff0c…

C 语言基本语法及实用案例分享

一、什么是 C 语言? C语言是一种较早的程序设计语言,诞生于1972年的贝尔实验室。1972 年,Dennis Ritchie 设计了C语言,它继承了B语言的许多思想,并加入了数据类型的概念及其他特性。C语言是一门面向过程的计算机编程语…

基于单片机和LabVIEW的多路数据采集系统设计

摘 要:以8位高速、低功耗微控制器STC12C5A60S2为硬件控制核心,以Labview为上位机软件开发平台,设计了一个多路数据采集系统。由下位机单片机对多路模拟信号量进行数据采集,通过串口将采集的模拟量信息上传到上位机,上位机Labview对采集的数据进行存储、显示及处理、分析…

Node.js中如何处理异步编程

在Node.js中,处理异步编程是至关重要的技能。由于Node.js的单线程执行模型,异步编程可以极大地提高程序的性能和响应速度。本文将介绍几种常见的异步编程处理方式,并附上示例代码,帮助您更好地理解和应用异步编程技术。 回调函数…

GitLab代码库提交量统计工具

1.说明 统计公司所有项目的提交情况,可指定分支和时间段,返回每个人的提交新增数、删除数和总数。 2.API 文档地址:http://公司gitlab域名/help/api/README.md 项目列表查询 返回示例: [{"id": 1, //项目ID"http…

软考29-上午题-【数据结构】-排序

一、排序的基本概念 1-1、稳定性 稳定性指的是相同的数据所在的位置经过排序后是否发生变化。若是排序后,次序不变,则是稳定的。 1-2、归位 每一趟排序能确定一个元素的最终位置。 1-3、内部排序 排序记录全部存放在内存中进行排序的过程。 1-4、外部…

TF-A之供应链威胁模型分析

目录 一、简介 二、TF-A 概述 2.1、TF-A 存储库 2.2、外部依赖 2.3、附加二进制文件 2.4、TF-A工具链 2.5、基础设施 三、TF-A数据流 四、攻击树 五、威胁评估与缓解 5.1、影响和可能性评级 5.2、威胁和缓解措施 六、附录 一、简介 软件供应链攻击旨在向软件产品…

《深入浅出 Spring Boot 3.x》预计3月份发版

各位,目前本来新书《深入浅出 Spring Boot 3.x》已经到了最后编辑排版阶段,即将在3月份发布。 目录: 现在把目录截取给大家: 主要内容: 本书内容安排如下。 ● 第 1 章和第 2 章讲解 Spring Boot 和传统 Spri…

IT资讯——全速推进“AI+鸿蒙”战略布局!

文章目录 每日一句正能量前言坚持长期研发投入全速推进“AI鸿蒙”战略 人才战略新章落地持续加码核心技术生态建设 后记 每日一句正能量 人总要咽下一些委屈,然后一字不提的擦干眼泪往前走,没有人能像白纸一样没有故事,成长的代价就是失去原来…

【东京都立大学主办多重会议奖项】第六届计算机通信与互联网国际会议

ICCCI 2024 - Hosted by Tokyo Metropolitan University, Japanhttps://www.iccci.org/ 会议简介 第六届计算机通信与互联网国际会议将于2024年6月14-16日在日本东京都立大学举行。ICCCI 2024由东京都立大学主办,华中师范大学和美国科学工程学会联合赞助、并得到了…

Curfew e-Pass 管理系统存在Sql注入漏洞 附源代码

免责声明:本文所涉及的信息安全技术知识仅供参考和学习之用,并不构成任何明示或暗示的保证。读者在使用本文提供的信息时,应自行判断其适用性,并承担由此产生的一切风险和责任。本文作者对于读者基于本文内容所做出的任何行为或决…

使用备份工具xtrabackup进行增量备份详细讲解

增量备份 第一次修改数据 mysql> insert into tb_user values (4,sxx,0); Query OK, 1 row affected (0.01 sec)mysql> select * from tb_user; ------------------- | id | name | sex | ------------------- | 1 | Tom | 1 | | 2 | Trigger | 0 | | …

深入学习TS的高阶语法(泛型、类型检测、内置工具)

文章目录 概要一.TS的类型检测1.鸭子类型2.严格的字面量类型检测 二.TS的泛型1.基本使用2.传递多个参数3.泛型接口4.泛型类5.泛型约束6.映射类型(了解) 三.TS的知识扩展1.模块的使用-- 内置类型导入 2.类型的查找3.第三方库的类型导入4.declare 声明文件…

深度学习中的样本分类:如何区分正样本、负样本、困难样本和简单样本?

深度学习中的样本分类:如何区分正样本、负样本、困难样本和简单样本? 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入…

思维导图教你工作日报怎么写?

工作日报撰写秘诀:轻松提升效率,让你的每一天都闪闪发光 在快节奏的现代工作中,如何高效地规划和管理工作任务成为了职场人士必须面对的挑战。思维导图作为一种强大的思维工具,正逐渐受到越来越多人的青睐。本文将探讨为什么使用…

MySQL 索引原理以及 SQL 优化

索引 索引:一种有序的存储结构,按照单个或者多个列的值进行排序。索引的目的:提升搜索效率。索引分类: 数据结构 B 树索引(映射的是磁盘数据)hash 索引(快速锁定内存数据)全文索引 …

opencv的图像上下、左右和对角线翻转—flip函数

在OpenCV中,flip函数用于翻转图像。你可以沿x轴、y轴或两者同时翻转图像。这个函数非常直接,可以用于创建镜像图像或旋转图像。 void flip(InputArray src, OutputArray dst, int flipCode);src:输入图像。 dst:翻转后的输出图像…

安卓系统和iOS系统的手机备忘录同步数据方法

在这个智能手机时代,安卓与iOS系统犹如两位王者,各自拥有庞大的用户群体。有人钟情于安卓的开放与多样,有人偏爱iOS的流畅与稳定。甚至,有些人为了满足不同需求,同时使用着两个系统的手机。我就是其中的一员。 工作中…

ELK 简介安装

1、概念介绍 日志介绍 日志就是程序产生的,遵循一定格式(通常包含时间戳)的文本数据。 通常日志由服务器生成,输出到不同的文件中,一般会有系统日志、 应用日志、安全日志。这些日志分散地存储在不同的机器上。 日志…