Java(六)——抽象类与接口

news2024/11/17 10:05:00

文章目录

  • 抽象类和接口
    • 抽象类
      • 抽象类的概念
      • 抽象类的语法
      • 抽象类的特性
      • 抽象类的意义
    • 接口
      • 接口的概念
      • 接口的语法
      • 接口的特性
      • 接口的使用
      • 实现多个接口
      • 接口与多态
      • 接口间的继承
      • 抽象类和接口的区别

抽象类和接口

抽象类

抽象类的概念

Java使用类实例化对象来描述现实生活中的实体,不过,不是所有的类都能描述实体的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类(准确来说,我们可以将这样的类设计成抽象类)。

以画图形为例,有如下代码:

//Shape.java
public class Shape {
    public void draw() {
        System.out.println("画一个图形");
    }
}

//Pentagram.java
public class Pentagram extends Shape {
    @Override
    public void draw() {
        System.out.println("五角星☆");
    }
}

//Rotundity.java
public class Rotundity extends Shape {
    @Override
    public void draw() {
        System.out.println("圆形⭕");
    }
}

我们在实现Shape类的draw方法时,由于Shape是一个宽泛的概念,不是一个具体的图形,所以我们实际上是没办法实现的,上代码中的实现也没有实际的意义,因此,我们可以将Shape类设计成抽象类,而对于Shape类中的draw方法,我们可以将它设计成抽象方法.


抽象类的语法

Java中,abstract修饰的类称为抽象类,抽象类中被 abstract修饰的方法称作抽象方法

抽象方法不用给出具体的实现。(这是强制的,不能给出方法体

将上面的Shape类设计成抽象类,draw方法设计成抽象方法:

//Shape.java
public abstract class Shape {
    public abstract void draw();
}

注意: 抽象类也是类,抽象类也可以有普通的成员方法、成员变量或构造方法。

抽象类与普通类的区别是抽象类有abstract修饰,且可以存在抽象方法(不存在也可以)。


抽象类的特性

  1. 抽象类不能实例化对象

    public class Test {
        public static void main(String[] args) {
            Shape shape = new Shape();//实例化抽象类,报错
        }
    }
    

在这里插入图片描述

抽象类虽然不能实例化,但是抽象类的引用可以引用其子类的对象

//Shape.java
public abstract class Shape {
    public abstract void draw();
}

//Pentagram.java
public class Pentagram extends Shape {
    @Override
    public void draw() {
        System.out.println("五角星☆");
    }
}

//Rotundity.java
public class Rotundity extends Shape {
    @Override
    public void draw() {
        System.out.println("圆形⭕");
    }
}

//Test.java
public class Test {
    public static void func(Shape shape) {
        shape.draw();
    }

    public static void main(String[] args) {
        Pentagram pentagram = new Pentagram();
        Rotundity rotundity = new Rotundity();

        Shape[] shapes = {pentagram, rotundity};

        //向上转型
        for(Shape shape : shapes){
            func(shape);
        }
    }
}
  1. 抽象类必须被继承,且继承抽象类的子类必须重写抽象类中的抽象方法,如果不想重写抽象方法,需要加abstract修饰。不过,一旦这个类被一个普通的类继承,则此普通类必须重写所有的抽象方法。

    public abstract class Test {
        public abstract void func1();
    }
    
    abstract class A extends Test {
        public abstract void func2();
    }
    
    class B extends A {
        @Override
        public void func1() {
            System.out.println("重写抽象类Test的抽象方法");
        }
    
        @Override
        public void func2() {
            System.out.println("重写抽象类A的抽象方法");
        }
    } 
    

    ​ 抽象类A继承了抽象类Test,普通类B继承了A,那么普通类B必须重写A 类和Test类中的所有抽象方法。

  2. 由于抽象方法必须被重写,所以抽象方法不能被privatefinalstatic修饰

  3. 抽象类中可以不包含抽象方法,但抽象方法必须在抽象类中

    public class Test {
        public abstract void func();
    }
    

    在这里插入图片描述

  4. 抽象类中可以存在构造方法,用于子类实例化时初始化父类的成员

    //Shape.java
    public abstract class Shape {
        public int a;
        //抽象类的构造方法
        public Shape(int a) {
            this.a = a;
        }
        public abstract void draw();
    }
    
    //Pentagram.java
    public class Pentagram extends Shape {
    
    
        public Pentagram(int a) {
            super(a);
        }
        @Override
        public void draw() {
            System.out.println("五角星☆");
        }
    }
    
    //Rotundity.java
    public class Rotundity extends Shape {
    
        public Rotundity(int a) {
            super(a);
        }
        @Override
        public void draw() {
            System.out.println("圆形⭕");
        }
    }
    
    //Test.java
    public class Test {
        public static void main(String[] args) {
            Shape shape = new Pentagram(20);
            System.out.println(shape.a);
        }
    }
    

    打印结果是:
    在这里插入图片描述


抽象类的意义

我们可能会有一个疑问,普通类也可以被继承,普通的成员方法也可以被重写,为什么要用抽象类和抽象方法呢?

抽象类中的抽象方法如果没有被重写,编译器会报错。 是的,使用抽象类和抽象方法的好处就是多了一层编译器的校验,能帮助我们检查抽象方法是否被重写。

抽象类不能被实例化。 很多引用场景,比如上面的画图形场景,其实际工作不应该由父类完成,而应由子类完成,此时误用父类编译器会报错。

总的来说,使用抽象类就是为了预防出错,并让我们尽早发现问题,充分利用编译器的校验,在实际开发中是非常有意义的。


接口

接口的概念

接口(英文:Interface),在JAVA编程语言中是一个抽象(引用)类型,是抽象方法的集合。一个类通过继承接口的方式,从而来继承接口的抽象方法。

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。

我们很容易联想到实际生活中电脑的USB接口,它是一个标准,符合这个标准,就可以与电脑交互(可以插U盘、鼠标等)。

Java中的接口也是公共行为的规范,我们在实现时,只要符合标准,就可以通用。所以,接口可以看作是:多个类的公共规范,是一种引用类型


接口的语法

接口的定义与类的定义类似,只需要把关键字class换成interface

接口只能被publicabstract修饰,abstract默认不显性显示,如果省略public则使用默认的访问权限

public interface 接口名 {
    //...
}
  • 接口的命名一般是以I开头
  • 接口的命名一般使用形容词词性的单词,这样就能显示出接口的标准

接口的特性

  1. 接口是一种引用类型,但是不能直接实例化对象(接口实际上比抽象类更加抽象),不过接口可以引用实现该接口的类的对象(向上转型)

        public static void main(String[] args) {
            ITest iTest = new ITest();//报错,不能直接实例化接口
            }
    

    在这里插入图片描述

    interface ITest {
        //待实现的方法
        void func();
    }
    
    class A implements ITest {
        @Override
        public void func() {
            System.out.println("类A实现的func");
        }
    }
    
    class NewTest {
        public static void main(String[] args) {
            //接口引用了A类对象
            ITest iTest = new A();
        }
    }
    
  2. 接口可以定义变量,且接口的成员变量都是publicstaticfinal修饰的,且接口定义的变量必须手动初始化

    即使我们不写修饰符,成员变量也默认被publicstaticfinal修饰

    public abstract interface ITest {
        //下面定义的变量都是由 public static final 修饰的(不论是否显性书写或写全)
        public int a = 1;
        static int b = 2;
        final int c = 3;
        int d = 4;
        public static int e = 5;
        static final int f = 6;
        public final int g = 7;
        public static final int h = 8;
    }
    
  3. 接口可以定义方法,接口的方法默认是publicabstract修饰的,属于抽象方法,不需要方法体。如果想要在接口中具体实现一个方法,那么它必须是由defaultstatic修饰

    public interface ITest {
        //以下写法的修饰符都是 public abstract(无论是否写或写全)
        void func0();
        public abstract void func1();
        public void func2();
        abstract void func3();
        
        //被default或static修饰的方法有具体的实现
        default void func4() {
            System.out.println("接口中被default修饰的方法有方法体");
        }
    
        static void func5() {
            System.out.println("接口中被static修饰的方法有方法体");
        }
    }
    
  4. 实现接口的类,必须重写接口中的所有抽象方法,如果此类不想重写接口中的抽象方法,则它必须由abstract修饰,一旦此类被另一个非抽象类继承,那么这个非抽象类必须重写所有未被重写的抽象方法

    interface IA {
        //接口抽象方法
        void abfunc1();
    }
    
    abstract class A implements IA {
        public void myA() {
            System.out.println("A类特有的方法");
        }
        //A类抽象方法
        abstract void abfunc2();
    }
    
    class B extends A {
        @Override
        public void abfunc1() {
            System.out.println("重写IA接口中的抽象方法");
        }
    
        @Override
        void abfunc2() {
            System.out.println("重写B类中的抽象方法");
        }
    }
    
  5. 接口中不能有静态代码块、构造代码块或构造方法

  6. 由于接口的成员方法默认都有public修饰,所以重写后的方法必须是public修饰(重写后的方法的访问权限要大于等于父类)

  7. 上述表述的重写严格来说不准确,不过,语法要求与重写一致(这里不必纠结,只要记住抽象方法要被重写即可)

  8. 接口文件的文件名必须与接口名相同,且接口文件编译后也是.class为后缀的字节码文件


接口的使用

接口不能直接实例化对象,接口的使用需要一个 “实现类” 来 实现 接口中的方法,要用到关键字implements

public classimplements 接口 {
    //...
}

接口与类之间implements实现关系,父类和子类之间extends继承关系

interface ITest {
    //待实现的方法
    void func();
}

class A implements ITest {
    @Override
    public void func() {
        System.out.println("类A实现的func");
    }
}

继承表达的是is A的关系,如狗是动物;接口表达的含义是具有xxx特性,如狗会跑


实现多个接口

Java中不支持多继承,不过一个类可以实现多个接口,这个类需要实现所有接口的抽象方法:

//ISwimming.java
public interface ISwimming {
    void swim();
}

//IRunning.java
public interface IRunning {
    void run();
}

//Dog.java
public class Dog implements IRunning, ISwimming {
    public String name;
    public int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    @Override
    public void swim() {
        System.out.println(this.name + "正在游泳");
    }
}
  • 一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类

一个类可以继承一个父类并同时实现多个接口:

//Animal.java
public class Animal {
    public String name;
    public int age;
}
//IRunning.java
public interface IRunning {
    void run();
}

//ISwimming.java
public interface ISwimming {
    void swim();
}

//Dog.java
public class Dog extends Animal implements IRunning, ISwimming {

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    @Override
    public void swim() {
        System.out.println(this.name + "正在游泳");
    }
}
  • 继承与实现都存在时,必须先写extends继承,后写implements实现
  • 对于上面的代码,理解一点:只要一个类实现了如IRunning接口,它就可以run(),而不必是动物。(有些废话,主要是强调接口使用)

接口与多态

Java中,接口可以实现多态,看如下代码:

//IEat.java
public interface IEat {
    void eat();
}

//Animal.java
public class Animal {
    public String name;
    public int age;
}

//Cat.java
public class Cat extends Animal implements IEat {

    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public void eat() {
        System.out.println(this.name + "正在吃猫粮...");
    }
}

//Dog.java
public class Dog extends Animal implements IEat {

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public void eat() {
        System.out.println(this.name + "正在吃狗粮...");
    }
}

//Test.java
public class Test {
    
    //体现多态
    public static void testEat(IEat iEat) {
        iEat.eat();
    }
    
    public static void main(String[] args) {
        testEat(new Dog("大哈", 2));//匿名对象
        testEat(new Cat("小猫", 3));
    }
}

对于上述代码,我们给同一个方法testEat传入不同的对象CatDog,打印结果不同:

在这里插入图片描述


接口间的继承

接口的继承相当于把所有的接口合并在一起。

接口间可以实现继承

//IExcellentQuality.java
public interface IExcellentQuality {
    void func1();
}

//IKind.java
public interface IKind extends IExcellentQuality {
    void func2();
}

上述代码逻辑上就是:善良的 是 品质优良的

  • 一个接口继承了另一个接口,子接口不实现父接口的抽象方法,而当一个非抽象类实现了子接口,那么这个类要重写子接口和父接口所有的抽象方法

    public class Person implements IKind {
        @Override
        public void func2() {
            System.out.println("kind");
        }
    
        @Override
        public void func1() {
            System.out.println("excellent quality");
        }
    }
    

Java中,类与类之间不可以实现多继承,但接口与接口之间可以实现多继承

比如以下例子,两栖动物既可以游泳又可以行走:

//IRunning.java
public interface IRunning {
    void run();
}

//ISwimming.java
public interface ISwimming {
    void swim();
}

//IAmphibious.java
public interface IAmphibious extends ISwimming, IRunning {
    void func();
}

【总结】

  • 一个接口继承了另一个接口,子接口不实现父接口的抽象方法,而当一个非抽象类实现了子接口,那么这个类要重写子接口和父接口所有的抽象方法
  • 接口与接口之间可以实现多继承

抽象类和接口的区别

抽象类中可以包含普通的方法和字段,这些字段和方法可以被子类直接使用(普通方法不需要被重写),而接口中不能定义普通的字段和方法,子类必须重写接口中的所有抽象方法。

在这里插入图片描述

几点具体的区别:

    1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行(除非被defaultstatic修饰)。
    1. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
    1. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。(从 Java8 开始接口中可以定义静态方法)
    1. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

另外,我们补充一下实现接口与继承的区别:

1.不同的关键字,即实现接口(implements),继承(extends);

2.(一个类只能继承一个父类,而一个方法可以实现多个接口) 在面向对象编程的时候只能是单继承,但是实现接口可以有多个,简单点说,就是实现接口可以有好多个,但是继承的中父类只能只有一个,因为父亲只有一个,这说明了继承在Java中具有单根性,子类只能去继承一个父类;

3.在接口中只能定义全局变量和抽象方法,而在继承中可以定义普通的属性、方法等等…

4.(接口中的抽象方法必须被重写,而继承中子类可以选择不重写父类的方法(不考虑父类是抽象类)) 当某个接口被实现的时候,在类中一定要重写接口中的抽象方法,而继承中子类可以选择是否重写父类的方法,不是强制的


以上就是对Java中抽象类和接口的所有介绍了,希望能给大家带来帮助!
接下来将会发布不少博客:Java实现简单的图书管理系统、介绍内部类、介绍String…

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

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

相关文章

[数据集][图像分类]家庭场景下的家具分类数据集1010张101类别

数据集类型:图像分类用,不可用于目标检测无标注文件 数据集格式:仅仅包含jpg图片,每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数):1010 分类类别数:101 类别名称:[“bath_bath”,“bath_heated_t…

java版CRM客户关系管理系统源码-CRM客户关系管理系统的技术架构与功能实现

CRM客户关系管理系统的技术架构与功能实现 一、引言 随着市场竞争的日益激烈,客户关系管理(CRM)已成为企业赢得市场、提升客户满意度、促 进业务增长的关键手段。本文旨在介绍一款先进的CRM客户关系管理系统的技术架构与功能实现&#xff0…

C++:类的内存分布

类的成员变量和方法是分开存储的,内存给类实例化出的对象开辟空间时只开辟成员变量所占用的空间。类中的所有方法(成员函数)都会放在代码区,所以类的大小一般只计算类中成员变量的对齐之后大小的综合(如果没有虚函数的…

Java设计模式 _行为型模式_观察者模式

一、观察者模式 1、观察者模式 观察者模式 ( Observer Pattern )是一种行为型模式。 常用于对象间存在一对多关系时,比如,当一个对象被修改时,需要自动通知它的依赖对象。 2、实现思路 (1)、定义被观察者的行为&…

ETLCloud中如何执行SQL脚本

SQL脚本 在数据库管理与数据分析的广阔领域中,SQL(Structured Query Language,结构化查询语言)脚本扮演着举足轻重的角色。作为一门专为关系型数据库设计的编程语言,SQL不仅能够执行数据的检索、更新、插入及删除等基…

算法与数据结构:二叉排序树与AVL树

ACM大牛带你玩转算法与数据结构-课程资料 本笔记属于船说系列课程之一,课程链接: 哔哩哔哩_bilibilihttps://www.bilibili.com/cheese/play/ep66799?csourceprivate_space_class_null&spm_id_from333.999.0.0 你也可以选择购买『船说系列课程-年度会…

便携式应急气象站:应急气象监测装备

TH-BQX5便携式应急气象站,作为现代气象监测的重要装备,以其独特的便携性、高效性和灵活性,在应急气象监测领域发挥着至关重要的作用。这类气象站不仅为灾害预警、环境保护、农业生产等多个领域提供了实时、准确的气象数据,还在突发…

uniapp通过Canvas绘制网格(心电图,坐标纸等可用)

本篇文档是Canvas绘制心电图的第一个部分&#xff0c;想了解详情的可以关注后学习交流。 心电图的最底层需要一个网状底层&#xff0c;来方便进行数据的测量。 一、白底分大、中、小三个区域的网格 1、首先是HTML部分 <!DOCTYPE html> <html lang"en">…

DNS设置(linux)

1.配置dns需要现在/etc/sysconfig/network-scripts/目录下的ifcfg-ens33(后面数字也可能是其他的)中配置DNS 2.编辑/etc/resolv.conf文件&#xff0c;将上面网卡中加的dns服务器ip添加到此文件 vi /etc/resolv.conf重启网络配置 service network restart常用的dns的ip 国内…

qt中实现多语言功能

qt中实现多语言功能 原理&#xff1a; 其本质就是生成ts文件&#xff0c;然后使用Linguist软件手工翻译&#xff0c;再生成qm文件&#xff0c;最后在主程序的开始加载不同的qm文件&#xff0c;实现多语言。 步骤&#xff1a; 修改程序文件 在pro文件中加入说明 TRANSLATI…

通讯录恢复怎么办?保护珍贵联系信息的2个必备技能!

手机通讯录扮演着重要的角色&#xff0c;它不仅仅是一个简单的联系方式列表&#xff0c;更是我们与亲朋好友、同事、业务伙伴等之间关系的见证。万一不慎丢失或误删通讯录&#xff0c;学会通讯录恢复的技能变得非常重要。本文将为你介绍几种保护珍贵联系信息的必备技能&#xf…

这样写代码太优雅了吧

文章目录 优化案例初次优化再次优化看看Spring源码的处理 优化案例 假设一个场景&#xff0c; 开发代码时&#xff0c;需要对类中的方法进行遍历&#xff0c;判断有没有注解NotNull&#xff0c;暂时没有合适的工具类&#xff0c;需要自己手搓一个。 无须多想&#xff0c;分分钟…

从GPT-3.5到GPT-4O:探索AI的进化之旅,哪一版更懂你?

如何评价GPT-4o? 最新的GPT-4O&#xff0c;被誉为GPT-4的增强版。它在保持前代产品优秀性能的基础上&#xff0c;大幅降低了使用成本&#xff0c;使得更多的普通用户也能享受到顶尖AI的服务。GPT-4O在非英语语言处理上的强化&#xff0c;更是让其在全球范围内的适用性大大提高…

使用Java和XxlCrawler获取各城市月度天气情况实践

目录 前言 一、历史数据获取 1、关于天气后报 2、信息界面分析 二、数据的提取开发 1、PageVo的定义 2、属性定义 3、实际信息抓取 三、信息抓取调试以及可能的问题 1、信息获取成果 2、关于超时的问题 四、总结 前言 这篇文章主要来源于一个我们家小朋友的一个作业…

FreeSwitch视频会议同时支持内网和外网接入

我们在使用freeswitch进行视频会议时&#xff0c;之前所有的用户都是通过外网的方式接入&#xff0c;因为fs给其返回的sdp协议内容里&#xff0c;只需要fs配置的外网IP就可以了&#xff1b;最近由于引入新的业务需要有其他内网的服务器也可以直接接入fs的视频会议房间&#xff…

【Spring Cloud】分布式配置

目录 未来的开发场景为什么需要配置中心配置实时生效配置管理流程 开源配置中心基本介绍DisconfSpring Cloud ConfigApolloNacos Spring Cloud Config介绍配置管理工具体系 案例需求编写 Config Server1.创建配置文件2.创建项目3.添加依赖4.添加注解5.修改配置文件application.…

玩游戏也能学好 JavaScript 啦?

最近有朋友问&#xff0c;应该如何学好 JavaScript。不过我做了好多年的后端开发&#xff0c;JavaScript 虽然也是有所接触&#xff0c;但肯定是谈不上精通。在将朋友介绍给公司的前端大神之后&#xff0c;突然想到&#xff0c;学习编程本身还是一个挺枯燥的事情&#xff0c;如…

FDW(Foreign Data Wrapper)

在上一篇博客里&#xff0c;最末尾提到了 FDW。 FDW 到底是什么呢&#xff1f; 标准 FDW&#xff08;Foreign Data Wrapper&#xff09;遵循了 SQL/MED 标准&#xff0c;标准全称&#xff1a;ISO/IEC 9075-9 Management of External Data (SQL/MED) 2003 年&#xff0c;SQL…

【大数据】Hadoop 2.X和1.X升级优化对比

目录 1.前言 2.hadoop 1.X的缺点和优化方向 3.解决NameNode的局限性 3.1.Hadoop HA 3.2.Haddop federation 4.yarn 5.周边组件 1.前言 本文是作者大数据系列中的一文&#xff0c;专栏地址&#xff1a; https://blog.csdn.net/joker_zjn/category_12631789.html?spm10…

相机系列——相机标定简述

作者&#xff1a;木一 对相机系列感兴趣还可看前文了解更多相关内容&#xff1a; 相机系列——透视投影&#xff1a;针孔相机模型 VR/AR/XR背后的逻辑&#xff1f;离不开三维引擎相机 引言 上文我们介绍了针孔相机模型&#xff0c;用来描述相机的透视投影成像过程&#xf…