分享

在Java代码中使用抽象类及接口(抽象类与接口的定义,使用与其作用详解)

 昵称70680357 2020-07-02

抽象类

语法规则:
首先我们来看一段代码:

class Shape{
    public void draw(){

    }
    }
class Cycle extends Shape{
    @Override
    public void draw(){
        System.out.println("⚪");
    }
}
class Rect extends Shape {
    @Override
    public void draw(){
        System.out.println("口");
    }
}
语言 方法
6603 2H5R0q4SBb
XHakg 抖音黄v
1883 2010-02-05 00:55:54

class Flower extends Shape {
    @Override
    public void draw(){
        System.out.println("♣");
    }
}
public class Test1 {
    public static void main(String[] args) {
        Shape shape1 = new Cycle();
        Shape shape2 = new Rect();
        Shape shape3 = new Flower();
        drawMap(shape1);
        drawMap(shape2);
        drawMap(shape3);
    }
    public static void drawMap( Shape shape){
        shape.draw();
    }
}

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

  • 在 draw 方法前加上 abstract 关键字, 表示这是一个抽象方法. 同时抽象方法没有方法体(没有 { }, 不能执行具体
    代码).
  • 对于包含抽象方法的类, 必须加上 abstract 关键字表示这是一个抽象类.

注意事项:

  1. 抽象类不能直接实例化.
  2. 抽象方法不能是 private 的.
  3. 抽象类中可以包含其他的非抽象方法, 也可以包含字段. 这个非抽象方法和普通方法的规则都是一样的, 可以被重写, 也可以被子类直接调用

抽象类的作用

  • 抽象类存在的最大意义就是为了被继承.

  • 抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.

    我们使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题.

接口

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含 静态常量.
语法规则:
在刚才的打印图形的示例中, 我们的父类 Shape 并没有包含别的非抽象方法, 也可以设计成一个接口
代码示例:

interface IShape{
    void draw();
}
class Cyle implements IShape {
    @Override
    public void draw(){
        System.out.println("⭕");
    }
}
class Square implements IShape{
    @Override
    public void draw(){
        System.out.println("▲");
    }
}
public class ShapTest {
    public static void main(String[] args) {
        IShape shap = new Cyle();
        shap.draw();
        IShape shap1 = new Square();
        shap1.draw();
    }
}
  • 使用 interface 定义一个接口

  • 接口中的方法一定是抽象方法, 因此可以省略 abstract

  • 接口中的方法一定是 public, 因此可以省略 public

  • Cycle 使用 implements 继承接口. 此时表达的含义不再是 “扩展”, 而是 “实现

  • 在调用的时候同样可以创建一个接口的引用, 对应到一个子类的实例.

  • 接口不能单独被实例化

    扩展(extends) vs 实现(implements)

       扩展指的是当前已经有一定的功能了, 进一步扩充功能. 实现指的是当前啥都没有, 需要从头构造出来.
    

接口中只能包含抽象方法. 对于字段来说, 接口中只能包含静态常量(final static).

interface IShape {   
    void draw();   
    public static final int num = 10; 
}

其中的 public, static, final 的关键字都可以省略,省略后的 num 仍然表示 public 的静态常量

提示:

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

实现多个接口
代码示例:

class Animal{  //定义一个动物的父类
    protected String name;
    public Animal(String name) {
        this.name = name;
    }
}
interface IFlying{  //一个会飞的接口
    void fly();
}
interface IRunning{   //一个会跑的接口
    void run();
}
interface ISwimming{   //一个会游泳的接口
    void swim();
}
//猫, 是会跑的
class Cat extends Animal implements IRunning{
    public Cat(String name){
       super(name);
    }
    @Override
    public  void run(){
        System.out.println(this.name + "正在用四条腿跑");
    }
}
//鱼, 是会游的
class Fish extends Animal implements ISwimming{
    public Fish(String name){
        super(name);
    }
    @Override
    public void swim(){
        System.out.println(this.name + " 正在用尾巴游");
    }
}
//青蛙, 既能跑, 又能游(两栖动物) 
class Frog extends  Animal implements ISwimming,IRunning{
    public Frog(String name){
        super(name);
    }
    @Override
    public void swim(){
        System.out.println(this.name + "正在蛙泳");
    }
    @Override
    public void run(){
        System.out.println(this.name + "正在往前跳");
    }
}
//还有一种神奇的动物, 水陆空三栖, 叫做 "鸭子"
class Duck extends  Animal implements IRunning,ISwimming,IFlying{
    public Duck(String name){
        super(name);
    }
    @Override
    public void run(){
        System.out.println(this.name + "正在用俩条腿跑");
    }
    @Override
    public void swim(){
        System.out.println(this.name + "正在用鸭掌游 ");
    }
    @Override
    public void fly(){
        System.out.println(this.name + "正在用翅膀飞");
    }
}
public class AnimalTest {
    public static void main(String[] args) {
       Cat cat = new Cat("小猫咪");
        cat.run();
       Fish fish = new Fish("小鱼儿");
       fish.swim();
       Frog frog = new Frog("小青蛙");
       frog.run();
       frog.swim();
       Duck duck = new Duck("小鸭子");
       duck.fly();
       duck.run();
       duck.swim();
    }
}

运行结果:
在这里插入图片描述
上面的代码展示了 Java 面向对象编程中最常见的用法: 一个类继承一个父类, 同时实现多种接口.

继承表达的含义是 is - a 语义, 而接口表达的含义是 具有 xxx 特性 .

  • 这样设计有什么好处呢?
    时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型, 而 只关注某个类是否具备某种能力.

接口间的继承

interface IRunning {
    void run();
}
interface ISwimming {
    void swim();
}
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {
    
}
class Frog implements IAmphibious {
    ...
}

通过接口继承创建一个新的接口 IAmphibious 表示 “两栖的”. 此时实现接口创建的 Frog 类, 就继续要实现 run 方法, 也需要实现 swim 方法.

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

总结:
抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别(重要!!! 常见面试题).

核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不 能包含普通方法, 子类必须重写所有的抽象方法.
在这里插入图片描述

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多