【Java】用一个动物王国的例子,讲清楚抽象类和接口

简介: 【Java】用一个动物王国的例子,讲清楚抽象类和接口

情景构造

抽象类示例:动物王国

为了方便大家理解抽象类和接口,我们先创建一个情景:

抽象类示例:动物王国

想象有一个庞大的动物王国,其中有很多种不同类型的动物。这些动物有一些共通的特性,比如都有名字,但它们的行为(如吃、睡觉)可能各不相同。这时,我们可以定义一个抽象类来表示这些动物的共通特性。

抽象类 Animal:

  • 有一个共通属性:name(所有动物都有名字)
  • 有抽象方法:eat() 和 sleep() (所有动物都会吃和睡觉,但具体怎么做各不相同)
public abstract class Animal {
    protected String name;
    
    public abstract void eat();
    public abstract void sleep();
    
}

在这个抽象类中,我们定义了动物的基本属性和它们应该有的行为,但没有给出具体的实现方法。这就是像在说:“所有的动物都会吃和睡觉,但没中动物的方式都不同,所以你们(子类)自己去实现吧。”

接口示例:技能接口

现在,假设在动物王国中,有些动物 具备特殊的技能,比如飞翔或者游泳。并不是所有的动物都会飞或游泳,而且这些节能的实现方式也各不相同。这时,我们可以使用接口来定义这些技能。

接口 Flyable:

  • 有一个方法:fly()(能飞的动物都会飞,但飞行方式各不相同)
public interface Flyable {  
    void fly();  
}

接口 Swimmable:

  • 有一个方法:swim()(能游泳的动物都会游泳,但游泳的方式各不相同)
public interface Swimmable {
    void swim();
}

接口在这里就像是一种“契约”。一个类实现了一个接口,就意味着它承诺提供接口中的方法的具体实现。我们的例子中,如果某个动物会飞,那么它就可以实现 Flyable 接口,并提供 fly() 方法的具体实现。同样,如果某个动物会游泳,它就可以实现 Swimmable 接口,并提供 swim() 方法的具体实现。

实现抽象类和接口

public class Bird extends Animal implements Flyable {  
    @Override  
    public void eat() {  
        System.out.println(getName() + " eats worms.");  
    }  
  
    @Override  
    public void sleep() {  
        System.out.println(getName() + " sleeps in a nest.");  
    }  
  
    @Override  
    public void fly() {  
        System.out.println(getName() + " flies with its wings.");  
    }  
}  
  
public class Fish extends Animal implements Swimmable {  
    @Override  
    public void eat() {  
        System.out.println(getName() + " eats algae.");  
    }  
  
    @Override  
    public void sleep() {  
        System.out.println(getName() + " sleeps at the bottom of the river.");  
    }  
  
    @Override  
    public void swim() {  
        System.out.println(getName() + " swims with its fins.");  
    }  
}

在这个例子中,Bird 类继承了 Animal 抽象类并实现了 Flyable 接口,因为它既能像其他动物一样吃和睡觉,也能飞。而 Fish 类继承了 Animal 抽象类并实现了 Swimmable 接口,因为它能游泳。通过这种方式,我们可以灵活地组合不同的行为和属性,来创建丰富多样的动物类型。

抽象类

抽象类的特性


  • 一个方法可以被修饰为abstract,此时代表这个方法可以不进行实现,此时被称为抽象方法
  • 若一个类中包含抽象方法,那这个类也必须是抽象类
  • 没有抽象方法,类也能被写为抽象类
  • 什么时候一个类可以被定义为抽象类?
  • 当一个类不能具体描述某个对象的时候
  • 抽象类中定义的成员可以和普通类中无区别
  • 抽象类不能实例化
  • 既然不能实例化,那存在的意义是什么?
  • 为了被继承
  • 当一个普通类继承抽象类后,必须重写抽象类中的抽象方法
  • 抽象类也能发生向上转型、动态绑定、重写
  • 此时抽象方法也需要满足重写的特点
  • 被 static 、final、private 修饰都是不能发生重载的
  • 可以理解为:abstract 和 final 是对立的
  • 当一个普通类 A 继承了一个抽象类,不想重写这个抽象类中的方法,此时可以把这个普通类 A 改为抽象类
  • 但是如果 A 这个抽象类再次被普通类 B 继承,此时 B 这个类需要重写所有未被重写的抽象方法(出来混,总是要还的)

作用


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

普通的类也能被继承呀,普通的方法也可以被重写呀,为什么非得用抽象类和抽象方法呢?

- 使用抽象类相当于多了一重编译器的校验

- 若实际工作不应该由父类完成,而是由子类完成,此时如果不小心误用成父类了,使用普通类编译器不会报错,但是父类是抽象类的话就会在实例化的时候提示错误,让我们可以尽早发现问题

Tips:

- 很多语法存在的意义都是为了“预防出错”,

- 例如我们使用过的 final 也是类似,若加上了 final 变量被不小心修改了,编译器就能及时提醒我们

- 充分利用编译器的校验,在实际开发中是非常有意义的

接口

概念

  • 接口就是公共的行为标准规范,大家在实现时,只要符合规范,就可以使用
  • 在 Java 中,接口可以看作是:多个类的公共规范,是一种引用数据类型

1. 接口的定义,可以使用 interface 定义(定义好后会生成一个单独的字节码文件)

创建接口时,接口的命名一般以大写字母 I 开头

  • 接口的命名一般使用“形容词”词性的单词
  • 阿里编码规范中约定,接口中的方法和属性不要加任何修饰符号,保持代码的简洁性

2. 接口当中的成员变量,默认为 public static final 修饰,定义的时候必须初始化,可以省略 怕public static final,

例如:public static final int a = 10;可以写为:int a = 10;

3. 接口中的方法默认是 public abstract 修饰的。你不写的时候,也是抽象方法,所以不能有具体的实现

4.接口当中,使用 default 修饰的方法和 static 修饰的方法是可以有具体实现的

public interface USB {
  double brand = 3.0; // 默认被:public static final修饰 
  void openDevice();
  void closeDevice(); 
} 
 
public class TestUSB implements USB{
  public static void main(String[] args) { 
    System.out.println(USB.brand); // 可以直接通过接口名访问,说明是静态的 
    
    USB.brand = 2.0; 
    //编译报错:Error:无法为最终变量brand分配值 
        //说明brand具有final属性 
  } 
}

5. 接口不能被实例化,它是抽象类,没有具体对象

public class TestUSB { 
  public static void main(String[] args) { 
    USB usb = new USB(); 
  } 
} // Error:USB是抽象的;无法实例化

6. 当接口需要被类实现,此时使用关键字 implements 来实现

例如:class TestUSB implements USB

7. 当一个类实现了一个接口,那么此时这个类就要重写接口中的方法

8.接口也可以发生向上转型、动态绑定、多态

接口的特性

1. 接口是一种引用类型,但不能直接 new 接口

2. 接口中每一个方法都是 public 的抽象方法,即接口中的方法会被隐式的指定为 public abstract(唯一的,其他修饰符都会报错)

3. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现

4. 重写接口中的方法时,不能使用默认的访问权限

5. 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量

6. 接口中不能有静态代码块和构造方法

7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀也是 .class

8. 如果类没有实现接口中的所有抽象方法,则类必须被设置为抽象类

实现多个接口

  • 类和类之间是单继承的,一个类只能有一个父类,即java中不支持多继承,但一个类可以实现多个接口
interface IA {
    void testA();
}
 
interface IB {
    void testB();
}
 
public class TestDemo implements IA,IB{  //同时实现IA和IB接口
    //这个类同时具备了IA和IB接口的行为,需要重写每一个方法
    @Override
    public void testA() {
        System.out.println("testA()");
    }
 
    @Override
    public void testB() {
        System.out.println("testB()");
    }
 
    public static void main(String[] args) {
        TestDemo t = new TestDemo();
        t.testA();
        t.testB();
    }
}

接口间的继承

  • 接口间的继承就相当于把多个接口合并在了一起
interface IA {
    void testA();
}
 
interface IB {
    void testB();
}
 
interface IC extends IA,IB {
    void testC();
}
 
public class TestDemo implements IC{ 
//不仅具备自己testC功能,还扩展了IA和IB的功能
    @Override
    public void testA() {
        System.out.println("testA()");
    }
 
    @Override
    public void testB() {
        System.out.println("testB()");
    }
    
    @Override
    public void testC() {
        System.out.println("testC()");
    }
}


相关文章
|
存储 编解码 负载均衡
通俗易懂讲解 nginx-rtmp-module 是干嘛的?
通俗易懂讲解 nginx-rtmp-module 是干嘛的?
628 0
|
JavaScript 前端开发
Playwright执行 JavaScript 脚本:探索浏览器自动化的新境界
在Web自动化中,Playwright提供`page.evaluate()`和`page.evaluate_handle()`来执行JavaScript脚本。`page.evaluate()`返回脚本执行结果,而`page.evaluate_handle()`返回JSHandle。示例展示了如何使用它们,如打印网页标题、操作元素及获取页面内容。通过这些方法,可以处理常规方法难以操作的网页元素。
|
安全 Linux Windows
深入理解操作系统内存管理:分页与分段的融合
【4月更文挑战第30天】 在现代操作系统中,内存管理是确保多任务环境稳定运行的关键。本文将深入探讨分页和分段两种内存管理技术,并分析它们如何相互融合以提供更为高效、安全的内存使用策略。通过对比这两种技术的优缺点,我们将探索现代操作系统中它们的综合应用,以及这种融合对操作系统设计和性能的影响。
1213 0
|
存储 监控 测试技术
【游戏】服务器性能测试(三) 性能指标
一、引言 在做游戏服务器性能测试的时候,我们需要通过一些指标来判断服务端是否存在性能问题,由于绝大多数的服务端都是架设在Linux服务器上,因此本篇是以Linux系统为前提,简单介绍常用的性能指标。 二、服务器指标 现如今的游戏服务器一般为分布式架构如图1。一个区的服务端由多个节点组成,通过这些节点来完成复杂的业务功能交互以及扩大人数承载。并不是每个节点都会占用一台物理机,通常是一个区的节点都放在一台物理机上(多区公用的除外)。这样每个节点进程就不能完全独占CPU,内存,网络等资源。而进行服务器性能测试也就是确保这些节点能够在一台机器上满足预定的设计要求。
2121 0
【游戏】服务器性能测试(三) 性能指标
|
安全 .NET Linux
jexus
Jexus web server V5.1 安装配置要点 一、Jexus简介:Jexus web server for linux 是一款基于.NET兼容环境,运行于Linux/unix操作系统之上,以支持ASP.NET为核心功能的高性能WEB服务器。
1885 0
|
缓存 开发工具 数据安全/隐私保护
git-学习git,这一篇就足够了(初学者视角实战教程)
git-学习git,这一篇就足够了(初学者视角实战教程)
603 0
|
Python
Python3 ‘str‘ object has no attribute ‘decode‘. Did you mean: ‘encode‘?
Python3 ‘str‘ object has no attribute ‘decode‘. Did you mean: ‘encode‘?
658 0
|
安全 测试技术 Nacos
Nacos Jraft Hessian反序列化远程代码执行漏洞
Nacos Jraft Hessian反序列化远程代码执行漏洞
2378 1
|
监控 安全 中间件
Python Django 后端架构开发: 中间件架构设计
Python Django 后端架构开发: 中间件架构设计
530 1
【高并发趣事一】——Amdahl(阿姆达尔定律)与Gustafson(古斯塔夫森定律)
【高并发趣事一】——Amdahl(阿姆达尔定律)与Gustafson(古斯塔夫森定律)
1155 0
【高并发趣事一】——Amdahl(阿姆达尔定律)与Gustafson(古斯塔夫森定律)

热门文章

最新文章