Java中的抽象类与接口介绍

Java抽象类与接口详解 什么是抽象类,什么是接口,其用法,通过本文,尽收眼底。 阅读详情

Java中的抽象类与接口

在Java中什么时候应该选择抽象类而不是接口?接受挑战吧!了解这些Java语言元素之间的区别以及如何在你的程序中使用它们。

在Java代码中,甚至在Java开发工具包(JDK)本身中,都有大量的抽象类和接口。每个代码元素都有一个基本的目的:

  • 接口是一种代码契约,必须由一个具体的类来实现。
  • 抽象类与普通类相似,不同的是它们可以包括抽象方法,也就是没有主体的方法。抽象类不能被实例化。

许多开发者认为接口和抽象类是相似的,但它们实际上是完全不同的。让我们来探讨一下它们之间的主要区别。

接口的本质

从本质上讲,接口是一个契约,所以它依赖于一个实现来达到其目的。一个接口永远不可能有状态,所以它不能使用可变的实例变量。一个接口只能使用最终变量。

何时使用接口

接口对[解耦代码和实现多态性非常有用。我们可以在JDK中看到一个例子,就是List 接口:


public interface List<E> extends Collection<E> {

    int size();
    boolean isEmpty();
    boolean add(E e);
    E remove(int index);
    void clear();
}

正如你可能注意到的,这段代码很短,而且描述性很强。我们可以很容易地看到方法的签名,我们将用一个具体的类来实现接口中的方法。

List 接口包含一个契约,可以由ArrayList,Vector,LinkedList, 和其他类来实现。

为了使用多态性,我们可以简单地用List 来声明我们的变量类型,然后选择任何一个可用的实例化。这里有一个例子:


List list = new ArrayList();
System.out.println(list.getClass());

 List list = new LinkedList();
 System.out.println(list.getClass());

下面是这段代码的输出:


class java.util.ArrayList
class java.util.LinkedList

在这种情况下,ArrayList,LinkedList, 和Vector 的实现方法都是不同的,这就是使用接口的一个很好的场景。如果你注意到许多类都属于一个父类,其方法动作相同,但行为不同,那么使用接口是个好主意。

接下来,让我们来看看我们可以用接口做的几件事。

重写一个接口方法

记住,接口是一种必须由具体类来实现的契约。接口方法是隐含的抽象的,也需要一个具体类的实现。

这里有一个例子:


public class OverridingDemo {
  public static void main(String[] args) {
    Challenger challenger = new JavaChallenger();
    challenger.doChallenge();
  }
}

interface Challenger {
  void doChallenge();
}

class JavaChallenger implements Challenger {
  @Override
  public void doChallenge() {
    System.out.println("Challenge done!");
  }
}

下面是这段代码的输出:


Challenge done!

注意这个细节,接口方法是隐式抽象的。这意味着我们不需要明确地将它们声明为抽象的。

常量变量

另一条要记住的规则是,一个接口只能包含常量变量。因此,下面的代码是可以的:


public class Challenger {

  int number = 7;
  String name = "Java Challenger";

}

注意,这两个变量都是隐含的final 和static 。这意味着它们是常量,不依赖于一个实例,而且不能被改变。

如果我们试图改变Challenger 接口中的变量,例如,像这样:


Challenger.number = 8;

我们会触发一个编译错误,像这样:


Cannot assign a value to final variable 'number'
Cannot assign a value to final variable 'name'

缺省方法

当默认方法在Java 8中被引入时,一些开发者认为它们会和抽象类一样。然而这并不正确,因为接口不能有状态。

默认方法可以有一个实现,而抽象方法则不能。默认方法是lambdas和流的伟大创新的结果,但我们应该谨慎使用它们。

JDK中使用默认方法的一个方法是forEach() ,它是Iterable 接口的一部分。我们可以简单地重用forEach 方法,而不是将代码复制到每个Iterable 的实现中:


default void forEach(Consumer<? super T> action) { 
  // Code implementation here…

任何Iterable 实现都可以使用forEach() 方法,而不需要新的方法实现。然后,我们可以用一个默认方法来重用代码。

让我们来创建我们自己的默认方法:


public class DefaultMethodExample {

  public static void main(String[] args) {
    Challenger challenger = new JavaChallenger();
    challenger.doChallenge();
  }

}

class JavaChallenger implements Challenger { }

interface Challenger {

  default void doChallenge() {
    System.out.println("Challenger doing a challenge!");
  }
}

下面是输出结果:


Challenger doing a challenge!

关于默认方法,需要注意的是,每个默认方法都需要一个实现。默认方法不能是静态的。

现在,让我们继续讨论抽象类。

抽象类的本质

抽象类可以有实例变量的状态。这意味着一个实例变量可以被使用和变异。这里有一个例子:


public abstract class AbstractClassMutation {

  private String name = "challenger";

  public static void main(String[] args) {
    AbstractClassMutation abstractClassMutation = new AbstractClassImpl();
    abstractClassMutation.name = "mutated challenger";
    System.out.println(abstractClassMutation.name);
  }

}

class AbstractClassImpl extends AbstractClassMutation { }

下面是输出结果:


mutated challenger

抽象类中的抽象方法

就像接口一样,抽象类可以有抽象方法。抽象方法是一个没有主体的方法。与接口不同,抽象类中的抽象方法必须明确地声明为抽象的。这里有一个例子:


public abstract class AbstractMethods {

  abstract void doSomething();

}

试图声明一个没有实现的方法,而且没有abstract 关键字,像这样:


public abstract class AbstractMethods {
   void doSomethingElse();
}

导致了一个编译错误,像这样:


Missing method body, or declare abstract

什么时候使用抽象类

当你需要实现可改变状态时,使用抽象类是一个好主意。作为一个例子,Java集合框架包括AbstractList类,它使用变量的状态。

在你不需要维护类的状态的情况下,通常使用一个接口更好。

实践中的抽象类

设计模式中的模板方法是使用抽象类的好例子。模板方法模式在具体方法中操作实例变量。

抽象类和接口的区别

从面向对象编程的角度来看,接口和抽象类的主要区别是,接口不能有状态,而抽象类可以用实例变量来有状态。

另一个关键区别是,类可以实现一个以上的接口,但它们只能扩展一个抽象类。这是一个基于多重继承(扩展一个以上的类)会导致代码死锁的设计决定。Java的工程师们决定要避免这种情况。

另一个区别是,接口可以被类实现,也可以被接口扩展,但类只能被扩展。

还需要注意的是,lambda表达式只能用于功能接口(指只有一个方法的接口),而只有一个抽象方法的抽象类不能使用lambdas。

接受Java代码挑战吧!

让我们通过一个Java代码挑战来探索接口和抽象类的主要区别。我们在下面提供了代码挑战,你也可以[用视频的形式观看抽象类与接口的挑战

在下面的代码中,同时声明了一个接口和一个抽象类,而且代码中还使用了lambdas:


public class AbstractResidentEvilInterfaceChallenge {
  static int nemesisRaids = 0;
  public static void main(String[] args) {
    Zombie zombie = () -> System.out.println("Graw!!! " + nemesisRaids++);
    System.out.println("Nemesis raids: " + nemesisRaids);
    Nemesis nemesis = new Nemesis() { public void shoot() { shoots = 23; }};

    Zombie.zombie.shoot();
    zombie.shoot();
    nemesis.shoot();
    System.out.println("Nemesis shoots: " + nemesis.shoots +
        " and raids: " + nemesisRaids);
  }
}
interface Zombie {
  Zombie zombie = () -> System.out.println("Stars!!!");
  void shoot();
}
abstract class Nemesis implements Zombie {
   public int shoots = 5;
}

你认为当我们运行这段代码时,会发生什么?请从下列选项中选择一个。

选项A


     Compilation error at line 4

选项B


     Graw!!! 0
     Nemesis raids: 23
     Stars!!!
     Nemesis shoots: 23 and raids:1

选项C


     Nemesis raids: 0
     Stars!!!
     Graw!!! 0
     Nemesis shoots: 23 and raids: 1

选项D


     Nemesis raids: 0
     Stars!!!
     Graw!!! 1
     Nemesis shoots: 23 and raids:1

选项E


    Compilation error at line 6

Java代码挑战视频

你为这个挑战选择了正确的输出吗?请观看视频或继续阅读以了解答案。

了解接口和抽象类及方法

这个Java代码挑战展示了许多关于接口、抽象方法等的重要概念。逐行浏览代码会让我们了解到输出中发生的很多事情。

代码挑战的第一行包括Zombie 接口的lambda表达式。请注意,在这个lambda中,我们正在增加一个静态字段。实例字段在这里也可以使用,但在lambda之外声明的局部变量就不行了。因此,到目前为止,这段代码可以正常编译。还要注意的是,lambda表达式还没有执行,所以nemesisRaids 字段还不会被递增。

在这一点上,我们将打印nemesisRaids 字段,它没有被增加,因为λ表达式还没有被调用,只是被声明。因此,这一行的输出将是:


Nemesis raids: 0

这个Java代码挑战中另一个有趣的概念是,我们正在使用一个匿名的内层类。这基本上意味着任何将实现Nemesis 抽象类的方法的类。我们并没有真正实例化Nemesis 抽象类,因为它实际上是一个匿名的类。还要注意的是,第一个具体的类在扩展它们的时候总是有义务实现抽象的方法。

在Zombie 接口里面,我们用一个lambda表达式声明了zombie static Zombie 接口。因此,当我们调用zombie shoot 方法时,我们会打印以下内容:


Stars!!!

下一行代码调用了我们在开始时创建的lambda表达式。因此,nemesisRaids 这个变量将被递增。然而,由于我们使用的是后增量运算符,它将只在这条代码语句之后被增量。接下来的输出将是:


Graw!!! 0 

现在,我们将从nemesis 中调用shoot 方法,这将改变其shoots 实例变量为23 。 注意,这部分代码展示了接口和抽象类之间的最大区别。

最后,我们打印nemesis.shoots 和nemesisRaids 的值。因此,输出结果将是:

Nemesis shoots: 23 and raids: 1

综上所述,正确的输出是选项C:


     Nemesis raids: 0
     Stars!!!
     Graw!!! 0
     Nemesis shoots: 23 and raids: 1
MMSE (Minimum Mean Square Error)均衡原理讲解 MMSE是一种将接收数据的MSE(均方误差)最小化的模型。有了这句话,很多问题就会在你的脑海中蹦出来。 什么是均方误差?最小化MSE "的物理含义是什么? 等等。 让我们从一个我们现在已经非常熟悉的通道模型开始。(我希望你现在也熟悉下面的表达方式。) MMSE作为一种均衡器,是一种后处理算法,它可以帮助我们找出接收到的数据,使之尽可能地接近原始数据(传输数据)。简而言之,MMSE中最重要的步骤是找到一个如下图所示的矩阵G。如果我们假设没有噪声,这个[G]矩阵可以简单的作为信道矩阵(H^-1)的倒数。但 阅读详情

相关推荐

改进爬山算法之六:随机重启爬山算法(Random-Restart Hill Climbing,RRHC)

随机重启爬山算法(Random-Restart Hill Climbing,RRHC)是爬山算法的一种改进策略,是一种启发式搜索算法,旨在通过随机重启来克服传统爬山算法容易陷入局部最优解的局限性,并增加找到全局最优解的概率。随机重启爬山算法通过在多次运行中不断尝试不同的初始解,并在每次运行中执行标准的爬山算法,最终选择所有运行中找到的最佳解作为最终结果。(1)计算复杂度:由于需要多次运行爬山算法,因此算法的计算复杂度可能较高,特别是在解空间较大或每次迭代需要较长时间的情况下。

搏博的专栏 2206

2.56.抽象类:有方法代码的接口

在 Java 8 中,接口中允许有缺省实现的抽象方法 看例程:不用抽象类,而是使用缺省方法的接口 // >> TODO 缺省的实现方法,用default修饰,可以有方法体 public interface ExpireDateMerchandise { // >> TODO 缺省的实现方法,用default修饰,可以有方法体 /** * 截止到当...

weixin_45471415的博客 147

深度学习驱动材料科学:晶体生成与性质预测技术综述

深度学习作为人工智能的核心技术,通过模拟人脑神经网络处理复杂数据,在多个领域展现出强大的模式识别与生成能力。其原理在于构建多层非线性变换,从海量数据中自动学习特征表示与映射关系。这一技术价值在于能够高效处理高维、非结构化数据,解决传统方法计算成本高、探索空间有限的问题。在工程实践中,深度学习已广泛应用于计算机视觉、自然语言处理等领域,并正深刻变革材料科学的研究范式。具体到材料领域,它通过学习已知材料的构效关系,实现对新材料性能的快速预测与逆向设计。应用场景包括但不限于新能源材料、半导体、催化剂等领域的高通量

weixin_28695161的博客 414

Java Missing method body, or declare abstract

增加枚举时,提示Missing method body, or declare abstract,需要将前面的;改为,即可。 改为 注意小细节~

程序员小彭的博客 5268

静态时序分析(Static Timing Analysis, STA):简介及内容导航

静态时序分析(简称STA)是用来验证数字设计时序的技术之一,另外一种验证时序的方法是时序仿真,时序仿真可以同时验证功能和时序。“时序分析”这个术语就是用来指代“静态时序分析“或”时序仿真“这两种方法之一,简单来说,时序分析的目的就是为了解决设计中的各种时序问题。STA被称为静态的原因是其对于设计的分析是静态地执行的,并不依赖于施加在输入端口上的激励。相比之下,时序仿真则可以被视作动态地执行对设计的分析,具体过程描述如下:施加一组激励,观察在这组激励下电路行为是否符合要求,然后换一组激。

Starry__的博客 1992

史上最全的Logisim运算器实验教程(基于华中科技大学计算机组成原理实验)

本博客是实现了Logisim的运算器设计,有具体的运算器设计的思路和运算器设计的电路,适合一步一步的按照思路做。

qq_62325622的博客 4万+

新增枚举类报错,Missing method body, or declare abstract

新增枚举类报错,Missing method body, or declare abstract

TianHao丶的学习之旅 911

10分钟极速SpringBoot项目搭建:OpenClaw AI实战攻略

OpenClaw,作为一款革命性的 AI 工具,凭借其强大的智能体能力,能够在短短 10 分钟内,帮助开发者从零构建一个完整的 SpringBoot 项目,实现真正的极速开发。它不仅极大地提高了开发效率,还降低了开发门槛,让更多的开发者能够专注于业务逻辑的实现,而无需被繁琐的配置工作所困扰

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 298

Java基础语法(九):抽象类和接口

在面向对象编程中,抽象类和接口是两种重要的概念,其定义和使用方式对于程序设计的质量和可维护性有着重要的影响。本文将介绍Java中抽象类和接口的基本概念、区别、使用场景以及代码示例,希望能够帮助读者更好地理解它们的概念与使用方式。一、抽象类抽象类(Abstract Class)是一种抽象的概念,其本身是一个类,但不能被直接实例化,而只能用作其子类的基类。抽象类可以定义抽象方法和具体方法,抽象方法指的是没有具体实现的方法声明,需要在子类中进行实现,具体方法则是已经实现的方法,子类可以直接调用它们。

分享是一种积极的生活态度~~ 1528

【Realtek sdk-3.4.14b】RTL8197FH+RTL8363NB当WAN/LAN IP冲突的时候,再次切换回正常的WAN,出现电脑无法上网也无法ping通设备网关问题分析及解决方案

如上图所示,当WAN和LAN网段冲突的时候,会导致路由设备异常,无法上网,但是修改为不冲突的网段之后,依然无法上网,同时下级PC也无法ping通路由设备,正常的如下图所示如上图所示,正常网络拓扑是可以正常的,但是在上级和路由LAN冲突的时候,再次切换为正常的网络也是异常问题复现步骤1.路由设备WAN口接到一个和本级路由是相同网段的设备2.拔掉WAN口,将WAN口接到一个和本级路由是不同网段的设备3.此时PC无法访问路由器。

wgl307293845的博客 665

全志 camera: 4路AHD摄像头转MIPI

TP2815 驱动模块主要实现将 4 路的 AHD/TVI/CVBS Camera 的数据转换为 MIPI 数据,从而实现在 T527 端来对数据进行处理和送显。

Linux驱动开发工程师,熟悉Linux/Android底层驱动、TP、显示、IIC、网络等通用外设调试适配,Linux上层应用开发。常用平台瑞芯微、全志、恩智浦等。 9095

Java基础:Java抽象接口

在Java中,一个没有方法体的方法应该定义为抽象方法,而如果一个类中含有抽象方法,则该类必须定义为一个抽象类。接口是功能的集合,同样可看做是一种特殊的数据类型,是比抽象类更为抽象的类,接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口的子类)来完成。这样将功能的定义与实现分离,优化了程序设计 本篇主要记录内容包括:抽象类、接口、抽象类和接口的差异、接口的新特性——默认方法和静态方法、 标记接口等相关内容

栗筝i的博客 5863

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Java抽象类和接口

本篇文章我们只谈了两件事:抽象类-接口。抽象类和接口是Java中两个非常重要的概念,它们各有独特的优势,共同特点是都很抽象。

LEE180501的博客 4655

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Java 抽象类和接口

文章目录一、抽象类1.抽象类1.1抽象类的定义1.2抽象方法的定义方式1.3抽象类的定义方式2.抽象类和实例类的区别3.抽象类示例4.抽象类的特征二、接口1.接口1.1接口的定义1.1定义一个接口1.2 接口的使用1.3接口的注意事项2.接口示例3.接口的特征三、抽象类和接口的区别 一、抽象类 1.抽象类 1.1抽象类的定义 在Java面向对象当中,所有的对象都是用过类进行描绘的,但是并不是所有的类都是用来描绘对象的,如果一个类没有包含足够多的信息来描述一个具体的对象,这样的类就是抽象类。 1.2抽象方法的

WYSCODER的博客 4869

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【Java SE】抽象类和接口

本期主要讲解: 1、抽象类 1.1 抽象类的概念 1.2 抽象类的语法 1.3 抽象类的特性 1.4 抽象类的作用 2、接口 2.1 接口的概念 2.2 接口的语法规则 2.3 接口的简单使用 2.4 接口的特性 2.5 实现多个接口 2.6 接口之间的继承 2.7 抽象类和接口的区别 3、Object 类 3.1 认识Object类 3.2 获取对象信息 3.3 对象的比较 equals 方法​​​​​​​......

程序猿教你打篮球的博客 1874

java之抽象类与接口

带你轻松了解抽象类与接口

G13138200303的博客 2001

Java中的接口以及抽象类与接口的关系

例如,`Duck`具有飞行和游泳的能力,所以`Duck`实现`Flyable`和`Swimmable`接口。- 在这个例子中,`Mammal`接口继承了`Animal`接口,这意味着实现`Mammal`接口的类不仅要实现`giveBirth`方法,还要实现`eat`方法。例如,`Circle`是一种`Shape`,所以`Circle`可以继承`Shape`抽象类。- 在这个`Shape`抽象类中,`color`是成员变量,`getColor`是普通的非抽象方法,`getArea`是抽象方法。

2301_77081232的博客 1326

Java中的抽象类与接口

抽象类与接口

2302_81707171的博客 2830

Java中的抽象类和接口

以下为示例代码中被abstract修饰的Shape类。

qq_62122428的博客 1300

java中抽象类和接口

当然有抽象类也有抽象方法,

有待提高 1159

Java接口和抽象类

Java中接口是很重要的

二哈喇子! 2665

Java中的接口及抽象类

两篇文章以不同的方式陈述了这个问题:文章1,转自:http://hi.baidu.com/klcstudy/blog/item/65e5333f129c0bec55e72313.htmlJava接口特性学习    在Java中看到接口,第一个想到的可能就是C++中的多重继承和Java中的另外一个关键字abstract。从另外一个角度实现多重继承是接口的功能之一,接口的存在可以使Ja

Day day up! 1万+

Java中抽象类与接口详解

private我们已经知道,抽象类就是为了被继承,但是private修饰的并不支持继承,自然抽象类中也不能有private修饰了finalfinal修饰的类不支持继承,所以也不能与抽象类中abstract在一起使用static抽象方法不能用static修饰,static修饰的方法是类级别的方法,不是对象级别的方法.而抽象类使用来被继承的.首先抽象类是半抽象的,接口是完全抽象的,这也决定了他们的不同1.一个类可以实现(implements)多个接口,但是一个普通类只能继承(extends)一个抽象类。

qm_hu的博客 1497
上一篇: JVM调优-GC基本原理和调优关键分析
下一篇: (纯干货,建议收藏)金九银十Java面试八股文及答案文档
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值