Java抽象类和接口

简介: Java抽象类和接口

前言


各位朋友们,大家好!今天我为大家分享的是Java的抽象类和接口,大家听到抽象类和接口可能就会想它到底有多抽象呢?很多初学者在学完了抽象类和接口之后可能大脑里面还没有抽象类和接口这个概念,也就像我们在学习离散数学的时候一样,课上跟着老师的步伐走可能当时能理解,但是每当下课铃声一响,你的脑子一片空白,并且在写老师布置的作业的时候会想:这个知识老师讲过了吗?大家别急,今天这篇文章我将带大家好好领略抽象类和接口的神奇之处。


抽象类


为什么会有抽象类这个概念


前面我们的大家可能都学过了继承,如果没学也别急,大家可以看看这篇文章Java继承(不能再留遗憾了)我们可以使用继承来将类的共性给提取出来作为父类来降低代码的复用率,但是我们想一想是不是有了继承就解决了一切呢?NO NO NO当然不是,我们来看一个例子:

class Animal {
    String name;
    float weight;
    public Animal(String name, float weight) {
        this.name = name;
        this.weight = weight;
    }
    public void Eat() {
        System.out.println(name+"吃猫粮");
    }
}
class Cat extends Animal{
    public Cat(String name, float weight) {
        super(name, weight);
    }
}
class Dog extends Animal {
    public Dog(String name, float weight) {
        super(name, weight);
    }
}
public class Main {
    public static void main(String[] args) {
        Cat cat = new Cat("小花",20);
        cat.Eat();
        Dog dog = new Dog("大黄",30);
        dog.Eat();
    }
}

image.png


我们都知道猫和狗一般都有名字,有体重等等,都会吃东西,所以我们将这些共性提取到Animal父类中,然后猫和狗继承Animal类也就继承了父类的成员变量和成员方法,但是当我们调用子类猫和狗的Eat方法时,我们会发现狗也吃猫粮?这显然是不合理的,因为就算他们都能吃东西,但是他们吃的食物的种类是不同的,我们在父类中将Eat的方法给实现了就太局限了,所以这里我们就出现了抽象类,抽象类可以很好的解决这个问题。


什么是抽象类


抽象类是指被abstract关键字修饰的类。抽象类中可以有普通的成员变量,可以有普通的成员方法也可以有抽象方法。抽象方法是指被abstract修饰的没有方法体的方法,这也就类似于我们C语言的函数的声明,这里只是告诉你我要使用这个方法,但是具体怎样使用,我不告诉你。抽象方法的实现需要你继承了这个子类来实现,我们的抽象方法不需要考虑这个。但是我们需要知道的是:既然他是抽象方法,什么是抽象?就是我们触摸不到的东西,是我们需要脑子想出来的东西,所以抽象类不能被实例化,也就是说抽象类无法使用new这个关键字实例出对象,他只能被子类继承,并且你的子类必须重写你父类的所有抽象方法,否则,你的子类也是一个抽象类。说到重写,我们知道你要想被重写就不能使用private和final来修饰你的抽象方法。


14.png

15.png


如果用private或者final来修饰你的抽象方法,编译器将会报错,这也会使你尽早发现你的错误。


16.png


当你的子类没有重写父类的所有抽象方法时,编译器同样会报错,你要不就是用abstract修饰这个类,使这个类也成为抽象类,但是你欠下的早晚都要还的,既然你的这个类是抽象类,你也需要别的类来继承你的这个抽象类,你要想别的类不为抽象类,你不仅需要重写这个类的抽象方法,还需要将这个类没有重写的父类抽象类的抽象方法重写,所以我们还是将这个抽象方法重写了最好。

abstract class Animal {
    String name;
    float weight;
    public Animal(String name, float weight) {
        this.name = name;
        this.weight = weight;
    }
    abstract void Eat();
}
class Cat extends Animal {
    public Cat(String name, float weight) {
        super(name, weight);
    }
    public void Eat() {
        System.out.println(name+"吃猫粮");
    }
}

我们使用抽象类来解决开头的问题。

abstract class Animal {
    String name;
    float weight;
    public Animal(String name, float weight) {
        this.name = name;
        this.weight = weight;
    }
    abstract void Eat();
}
class Cat extends Animal {
    public Cat(String name, float weight) {
        super(name, weight);
    }
    public void Eat() {
        System.out.println(name+"吃猫粮");
    }
}
class Dog extends Animal {
    public Dog(String name, float weight) {
        super(name, weight);
    }
    public void Eat() {
        System.out.println(name+"吃狗粮");
    }
}
public class Main {
    public static void main(String[] args) {
        Cat cat = new Cat("小花",20);
        cat.Eat();
        Dog dog = new Dog("大黄",30);
        dog.Eat();
    }
}

17.png


见识到抽象类的功能强大了没,既然抽象类就这么强大,那么我们来看看比抽象类更加抽象的-接口。


接口

什么是接口


为什么说接口是比抽象类更加抽象呢?因为在抽象类中可以有普通成员变量和方法,但是在接口中不存在普通的成员变量和普通方法,接口中只能有被public static final修饰的成员变量和public abstract修饰的抽象方法,但是在JDK8之后接口中可以存在default修饰的普通方法。


接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。


在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。


如何定义接口以及如何实现接口


定义一个接口


在定义接口的时候,我们只需要将定义类的时候的class换成interface就可以了。

public interface 接口名称{
  public static final int a;
  int b;
// 抽象方法
  public abstract void method1(); // public abstract 是固定搭配,可以不写
  public void method2();
  abstract void method3();
  void method4();
// 注意:在接口中上述写法都是抽象方法,跟推荐方式4,代码更简洁
}

我们在定义成员变量或者方法时可以将public static final 和public abstract省略,在接口中成员方法会被默认为public static final修饰的,抽象方法也会被默认为public abstract。并且通常接口的名称是以“I”开头的。


实现接口


跟继承类似,我们用implements关键字来实现接口。

public class 类名称 implements 接口名称{
  // ...
}
public interface IRunning {
    void running();
}
public interface ISwimming {
    void swimming();
}
public interface IFlying {
    void flying();
}
class Cat implements IRunning {
    @Override
    public void running() {
        System.out.println("猫会走");
    }
}
class Fish implements ISwimming {
    @Override
    public void swimming() {
        System.out.println("鱼会游泳");
    }
}
class Bird implements IFlying {
    @Override
    public void flying() {
        System.out.println("鸟会飞");
    }
}
public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.running();
        Fish fish = new Fish();
        fish.swimming();
        Bird bird = new Bird();
        bird.flying();
    }
}

image.png


我们定义不同的接口,那些类具有这些特性,需要使用它,就直接实现它,这极大的提高了代码的灵活性。


实现多个接口


不仅如此,我们一个类还可以实现多个接口,这也可以说是解决了Java不能多继承的问题。

class frog implements ISwimming,IRunning {
    @Override
    public void swimming() {
        System.out.println("青蛙会游泳");
    }
    @Override
    public void running() {
        System.out.println("青蛙会走");
    }
}

接口之间的继承关系


接口与接口之间可以有继承关系,并且接口与接口之间可以多继承,也可说是接口的拓展。

public interface IRunning {
    void running();
}
public interface ISwimming {
    void swimming();
}
public interface IAmphibious extends IRunning,ISwimming{
}
class frog implements IAmphibious {
    @Override
    public void swimming() {
        System.out.println("青蛙会游泳");
    }
    @Override
    public void running() {
        System.out.println("青蛙会走");
    }
}

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


抽象类和接口的区别

抽象类和接口都是Java中用于实现抽象类的机制,它们都不能被实例化,但是在使用方式、语法和用途方面有所不同。


1.实现方式

抽象类用关键字abstract来定义,包含普通方法、抽象方法、成员变量、成员方法和构造函数等,并且可以包含非抽象的方法实现。而接口是一组没有实现的特定方法集合,用关键字interface来定义,它不能包含非常量的成员变量,只能包含方法签名和常量。


2.继承方式

一个类只能继承一个抽象类,因为Java不支持多重继承。而接口支持多重继承,因为一个类可以实现多个接口。


3.方法实现方式

在抽象类中,可以有非抽象的方法实现,子类可以直接继承和使用这些方法。而在接口中,所有的方法都是抽象的,必须在实现类中实现所有的方法。


4.操作能力

抽象类可以作为一个实现类,它可以有一些已经实现好的方法,而且也可以定义一些抽象的方法,由子类实现。而接口只是一个描述行为的规范,不能有方法实现。只有某个类实现了这个接口,才能使用该接口中定义的方法。


5.应用场景

抽象类通常用于为所有的子类提供公共的方法或属性,在框架和类库的设计中较为常见。而接口通常用于定义与实现类无关的、普适性的方法,更多地用于描述类之间的通信、约定和功能规范。

综上所述,虽然抽象类和接口都是Java中实现抽象类的机制,但是它们的设计目标、实现方式、继承方式、方法实现方式以及应用场景等方面存在一些明显的差别。


总结

在Java中,抽象类和接口都是用于定义抽象类、协议或规范的工具。抽象类用于为所有子类提供一个公共的接口,它通过定义抽象方法、非抽象方法、变量和常量等实现这种目的。接口则是一组没有实现的特定方法集合,通过实现接口,一个类可以定义一组行为或功能规范,而不需要对其进行具体实现。在实际编程中,应该根据具体的业务需求选择合适的方式来进行定义和实现。


相关文章
|
3月前
|
数据采集 JSON Java
Java爬虫获取1688店铺所有商品接口数据实战指南
本文介绍如何使用Java爬虫技术高效获取1688店铺商品信息,涵盖环境搭建、API调用、签名生成及数据抓取全流程,并附完整代码示例,助力市场分析与选品决策。
|
3月前
|
消息中间件 缓存 前端开发
从资损百万到零事故:Java 接口幂等设计的艺术与实践
在分布式系统中,重复请求常引发严重资损,如支付双扣、库存超卖等问题,其根源在于接口缺乏幂等性设计。本文通过真实案例揭示幂等性的重要性,并详解8种主流解决方案,涵盖唯一请求ID、乐观锁、悲观锁、状态机等,帮助开发者构建稳定系统,保障业务一致性。无论你是架构师还是开发工程师,都能从中获得实战指导,有效规避重复调用带来的风险。
276 2
|
1月前
|
Java Go 开发工具
【Java】(9)抽象类、接口、内部的运用与作用分析,枚举类型的使用
抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体。抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接 口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类abstract static不能同时修饰一个方法。
206 0
|
2月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
141 11
|
3月前
|
存储 缓存 安全
Java集合框架(二):Set接口与哈希表原理
本文深入解析Java中Set集合的工作原理及其实现机制,涵盖HashSet、LinkedHashSet和TreeSet三大实现类。从Set接口的特性出发,对比List理解去重机制,并详解哈希表原理、hashCode与equals方法的作用。进一步剖析HashSet的底层HashMap实现、LinkedHashSet的双向链表维护顺序特性,以及TreeSet基于红黑树的排序功能。文章还包含性能对比、自定义对象去重、集合运算实战和线程安全方案,帮助读者全面掌握Set的应用与选择策略。
261 23
|
3月前
|
安全 Java 开发者
Java集合框架:详解Deque接口的栈操作方法全集
理解和掌握这些方法对于实现像浏览器后退功能这样的栈操作来说至关重要,它们能够帮助开发者编写既高效又稳定的应用程序。此外,在多线程环境中想保证线程安全,可以考虑使用ConcurrentLinkedDeque,它是Deque的线程安全版本,尽管它并未直接实现栈操作的方法,但是Deque的接口方法可以相对应地使用。
238 12
|
3月前
|
存储 安全 Java
Java集合框架(一):List接口及其实现类剖析
本文深入解析Java中List集合的实现原理,涵盖ArrayList的动态数组机制、LinkedList的链表结构、Vector与Stack的线程安全性及其不推荐使用的原因,对比了不同实现的性能与适用场景,帮助开发者根据实际需求选择合适的List实现。
|
3月前
|
Java API 网络架构
java调用api接口自动判断节假日信息
java调用api接口自动判断节假日信息
1301 0
|
4月前
|
存储 安全 Java
深入理解Java序列化接口及其实现机制
记住,序列化不仅仅是把对象状态保存下来那么简单,它涉及到类的版本控制、安全性和性能等多个重要方面。正确理解和实现Java序列化机制对于构建高效、安全和可维护的Java应用至关重要。
195 0