当前位置: 首页 > article >正文

【Java 学习】:抽象类接口

✨                                                 人逢喜事精神爽,月到中秋分外明       🌏 

📃个人主页:island1314

🔥个人专栏:java学习

⛺️  欢迎关注:👍点赞 👂🏽留言 😍收藏  💞 💞 💞


1. 抽象类

1.1 抽象类是什么

💢💢在Java中,一个类如果被 abstract 修饰称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法,抽象方法不用给出具体的实现体。

我们先来看一个简单的例子🌰

// 抽象类和抽象方法需要被 abstract 关键字修饰
abstract class Animal {
    // 抽象类中的方法一般要求都是抽象方法,抽象方法没有方法体
    abstract void eat();
    // 抽象类也是类,也可以增加普通方法和属性
    public double getArea(){
        return area;
    }
    protected double area; // 面积
}

初看上面是不是没啥问题,但是当我们对这个类进行实例化的时候,就会发现:

像这样的类是不是就没有包含足够的信息来描绘一个具体的对象,因此也就不能直接去实例化对象了。那我们应该怎么解决这个实例化问题呢?

// 抽象类和抽象方法需要被 abstract 关键字修饰
abstract class Animal {
    // 抽象类中的方法一般要求都是抽象方法,抽象方法没有方法体
    abstract void eat();
    // 抽象类也是类,也可以增加普通方法和属性
    public double getArea(){
        return area;
    }
    protected double area; // 面积
}
public class Test{
    public static void main(String[] args) {
        Animal animal = new Animal() {
            @Override
            void eat() {
                System.out.println("重写");
            }
        };
    }
}

只需要对 abstract类的抽象方法实例化之后进行重写即可。

注意:抽象类也是类,内部可以包含普通方法和属性,甚至构造方法

1.2 抽象类特性

🍉抽象类不能直接实例化对象,无法创建对象,抽象类是被子类来继承的

Animal animal = new Animal();
// 编译出错
Error:(30, 23) java: Animal是抽象的; 无法实例化

🥑抽象方法不能是 private 的

abstract class Animal {
    abstract private void eat(); //抽象方法不能是 private 的
}
// 编译出错
Error:(4, 27) java: 非法的修饰符组合: abstract和private

🥝抽象方法不能被final和static修饰,因为抽象方法要被子类重写

public abstract class Animal {
  abstract final void methodA();
  abstract public static void methodB();
}
// 编译报错:
// Error:(20, 25) java: 非法的修饰符组合: abstract和final
// Error:(21, 33) java: 非法的修饰符组合: abstract和static

🍋‍🟩抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰

abstract class Animal {
    abstract void eat();
    // 抽象类也是类,也可以增加普通方法和属性
    public double getArea(){
        return area;
    }
    protected double area; // 面积
}

class Dog extends Animal{
    @Override
    void eat() { 
        // 重写
    }
}

abstract class Cat extends Animal{
    
}

🥬其他特性:

  • 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
  • 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量

1.3 抽象类的应用

🍅那既然一个类不能直接实例化,那这种抽象类存在的意义是什么呀🤔?我们接着往下看

🍅抽象类存在的一个最大意义就是被继承,当被继承后就可以利用抽象类实现多态。

代码示例如下:

class Dog extends Animal{
    @Override
    void eat() {
        System.out.println("小狗吃东西");
    }
}

public class Test {
    public static void main(String[] args) {
        //Animal animal = new Animal(); // 抽象类虽然无法直接实例化
        // 但可以把一个普通类对象传给一个抽象类的引用呀,即父类引用指向子类对象
        Animal animal = new Dog(); // 这称作:向上转型
        /*Dog dog = new Dog();
        Animal animal = dog; // 这是向上转型的另一种写法*/

        animal.eat();         // 通过父类引用调用被子类重写的方法
    }
}

向上转型的具体,我们之前在多态那篇博客【Java 基础】:三大特征之多态-CSDN博客那就已经讲过,就不过多讲解了,只需要知道向上转型是:父类引用指向子类对象

1.4 抽象类的总结

抽象类是类和类之间的共同特征,将这些共同特征进一步形成抽象类,由于类本身不存在,所以抽象类无法创建对象。
类到对象是实例化,对象到类是抽象
抽象方法不能被 final 修饰,因为抽象方法就是被子类实现的

  • 采用 abstract 关键字定义的类就是抽象类,采用 abstract 关键字定义的方法就
    是抽象方法
  • 抽象的方法只需在抽象类中,提供声明,不需要实现
  • 如果一个类中含有抽象方法,那么这个类必须定义成抽象类。抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中
  • final和abstract不能同时同时使用,这两个关键字是对立的
  • 抽象方法不能被private修饰
  • 抽象类的子类可以是抽象类。也可以是非抽象类
  • 一个非抽象的类,继承抽象类,必须将抽象类中的抽象方法进行覆盖/重写/实现

抽象方法表示没有实现的方法,没有方法体的方法

  1. 没有方法体,以分号结尾
  2. 前面的修饰符列表中有abstract关键字,比如public abstract void dosome();

但是不能说java语言中没有方法体的方法都是抽象方法。
因为Object类中就有很多方法都没有方法体,都是以“;”结尾的,但他们都不是抽象方法

2. 接口 

2.1 接口是什么

🍑抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(Interface)🤔。

📝接口是Java中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成😎。

  • 接口是一种“引用数据类型”,完全抽象的,支持多继承,且一个接口可以继承多个接口,只有常量+抽象方法
  • 所有的元素都是public修饰的,抽象方法的public abstract可以省略,常量的public static final可以省略,方法不能有方法体

如何定义一个接口呢?下面我们来看一个栗子🌰

// 定义格式如下:
//[修饰符列表] interface 接口名{}

// 实例:
public interface Test{
    // 定义变量
    int a = 10;      // 接口当中的成员变量默认都是public static final

    // 抽象方法
    public abstract void metho(); // public abstract 是固定搭配,可以不写
    void method();  //  接口当中的成员方法默认都是public abstract, 更推荐用第二种来定义方法
}

提示:

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

2.2 接口的使用 

接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法

/* 语法格式 */
/* class 类名称 implements 接口名称{
// ...
} */

//实例
interface USB {
    void openDevice(); // 默认是public的
    void closeDevice(); // 默认是public的
}

class Mouse implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }
    @Override
    public void closeDevice() {
    }
    // ...
}

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

2.3 接口的特性

🍉接口类型是一种引用类型,但是不能直接new接口的对象

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

🥑接口中每一个方法都是public的抽象方法,所以不能有方法体。 即接口中的方法会被隐式的指定为 public abstract(只能是public abstract,其他修饰符都会报错)

//定义抽象方法的时候可以省略修饰符public abstract
public interface USB {
  // Error:(4, 18) java: 此处不允许使用修饰符private
  private void openDevice();
  void closeDevice();
}

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

public interface USB {
  void openDevice();
 
  // 编译失败:因为接口中的方式默认为抽象方法
  // Error:(5, 23) java: 接口抽象方法不能带有主体
  void closeDevice(){
    System.out.println("关闭USB设备");
 }
}

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

/* 语法格式 */
/* public class 类名称 implements 接口名称{
// ...
} */

//实例
interface USB {
    void openDevice(); // 默认是public的
}

class Mouse implements USB {
    @Override
    void openDevice() { //解决:函数前加个权限 public 即可
        System.out.println("打开鼠标");
    }
}
// 编译报错,重写USB中openDevice方法时,不能使用默认修饰符
// 正在尝试分配更低的访问权限; 以前为public

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

interface USB {
    double brand = 3.0; // 默认被:final public static修饰
    void openDevice();
    void closeDevice();
}
public class Test {
    public static void main(String[] args) {
        System.out.println(USB.brand); // 可以直接通过接口名访问,说明是静态的

        // 编译报错:Error:(12, 12) java: 无法为最终变量brand分配值
        USB.brand = 2.0; // 说明brand具有final属性,无法被再次赋值
    }
}

🍀支持多继承,且一个接口可以继承多个接口,每一个interface 都会生成一个class后缀名的文件 

interface a{
}

interface b extends a{
}

interface c extends a,b{
}

🥬其他特性:

  • 接口中不能有静态代码块和构造方法
  • 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
  • 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
  • jdk8中:接口中还可以包含default方法。

2.4 接口的应用

 通过接口实现多态

🍌刚才我们是用抽象类来实现多态,那么现在我们来尝试使用接口去实现多态😎

interface Animal{
    int a = 10;   //接口当中的成员变量默认都是public static final
    int b = 23;
    void eat();  //接口当中的成员方法一般只能是抽象方法,默认是public abstract(JDK1.8以前)

    default void show() {
        System.out.println("接口中的其他方法");//接口中的其他方法也可以实现,但要用default修饰
    }
    public static void test() {
        System.out.println("这是接口当中的一个静态的方法");
    }
}

// 一个普通的类要想实现接口,可以用implement,
//因为接口也是抽象方法的,所以实现接口的这个类也要重写抽象方法
class Dog implements Animal{
    @Override
    public void eat() {
        System.out.println("小狗");
    }
}

class Cat implements Animal{
    @Override
    public void eat() {

    }
}

public class Test{
    public static void main(String[] args) {
        Animal[] animals = {new Dog(),new Cat()};
        for(Animal animal: animals){
            animal.eat();
        }
    }
}

2.5 接口总结

  1. 接口是抽象化的,不能实例化
  2. 接口抽象方法必须实现,默认修饰 public abstract
  3. 接口属性是被 public static final 修饰,静态的、不可修改的
  4. 接口没有构造方法
  5. 接口有静态方法,含有方法体,主要特点是使用接口名调用静态方法
  6. 接口有默认方法,含有方法体,主要目的是为了扩展性和复用性

📖 总结

Java中接口和抽象类的定义语法分别为interface与abstract关键字。

相同点:

  • 都不能被实例化 ,接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。

不同点:

  1. 抽象类中的抽象方法的修饰符只能为public或者protected,默认为public;接口中的方法默认使用public修饰
  2. 抽象类可有成员变量,接口只能有 public static final 修饰的常量:接口成员变量默认为public static final,必须赋初值,不能被修改。抽象类中成员变量默认default,可在子类中被重新定义,也可被重新赋值;
  3. 实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。所以,使用接口可以间接地实现多重继承。
  4. 接口强调特定功能的实现,而抽象类强调所属关系。
  5. 抽象类可有构造函数,接口没有构造函数:抽象类可以包含方法、构造方法,方法可以实现,但是构造方法不能用于实例化,主要用途是被子类调用。接口只有定义,不能有方法的实现,java 1.8中可以定义default方法体。

💞 💞 💞那么本篇到此就结束,希望我的这篇博客可以给你提供有益的参考和启示,感谢大家支持!!!祝大家天天开心


http://www.kler.cn/a/294076.html

相关文章:

  • 探索SAP财务管理软件:重塑企业财务管理新境界
  • 【NLP】医学搜索Query相关性判断【阿里云:天池比赛】
  • sealos部署K8s,安装docker时master节点突然NotReady
  • 《Python Web 抓取实战:豆瓣电影 Top 250 数据抓取与分析》
  • 【项目组件】第三方库——websocketpp
  • MySQL高级(二):一条更新语句是如何执行的
  • 未来出行:高效智能的汽车充电桩
  • CUB-200-2011数据集及该格式自己数据集制作
  • 好用的AI编程助手MarsCode[豆包]
  • 分类预测|基于CNN-LSTM-Attention卷积-长短时记忆-注意力数据分类Matlab程序 直接运行程序或替换数据集运行程序
  • 基于IMX6ULL的Cortex-A中断原理讲解,以及编写其中断向量表
  • 算法图解(8~10贪心,动态规划,K最近邻算法)
  • 代码随想录训练营day36|1049.最后一块石头的重量II,494.目标和,474.一和零
  • WEB服务与虚拟主机/IIS中间件部署
  • 【kafka】在Linux系统中部署配置Kafka的详细用法教程分享
  • Leetcode面试经典150题-210.课程表II
  • 如何让linux程序在后台执行
  • CSP-J 之C++常用英文缩写
  • 【亲测有效】nginx负载均衡指定ip端口转发,做自动切换
  • 用Python实现时间序列模型实战——Day 13: 自回归条件异方差模型 (ARCH/GARCH)
  • 《深度学习》OpenCV轮廓检测 轮廓近似 解析及实现
  • Linux date命令 日期格式化与计算
  • VScode 的下载安装及常见插件 + Git的下载和安装
  • 2024年四川省安全员A证证考试题库及四川省安全员A证试题解析
  • 数据结构(1)数据结构基础(单向链表)
  • 双雄并肩:Tesla P40 GTX 1650 AI工作站搭建指南