热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

初识ADT抽象数据类型

主人Github主页ADT(抽象数据类型)1.认识接口(interface)接口是java程序设计中的一种抽象的数据类

主人Github主页


ADT(抽象数据类型)


1.认识接口(interface)

接口是java程序设计中的一种抽象的数据类型,我们可以通过对某接口的实施来具体到某一类的实现,也就是说我们可以通过对一个接口不同的实现来设计出满足不同要求的我们需要的class。

举个例子,

List list &#61; new ArrayList<>();

这个例子中&#xff0c;List声明为一个接口&#xff0c;由interface关键字标识&#xff0c;而ArrayList是就是实现了List这个接口的具体的类。

关于接口这种抽象的数据类型&#xff0c;其内定义的方法只有方法名和参数列表&#xff0c;而没有实体&#xff0c;&#xff08;除非你定义了一个静态方法&#xff0c;否则都将是不可用的没有实体的方法&#xff09;&#xff0c;比如像这样&#xff1a;
在这里插入图片描述
看到了&#xff0c;接口类型中的方法并没有实体&#xff0c;只是说我声明了这样一个方法&#xff0c;我有关于这个方法的规约&#xff08;简要说是对一个方法的说明&#xff0c;详细说明详见主人博客&#xff09;&#xff0c;方法的名称和参数列表&#xff0c;而没有方法的具体实现。

形象一点说&#xff0c;这可以是一个模板。好比一个List的接口能派生出两个具体实现的类&#xff08;ArrayList&#xff0c;LinkedList&#xff09;一样&#xff0c;你定义的接口也可以通过不同类的实施去达到派生出不同类的效果。但是注意&#xff01;你的实现必须都能等价到接口中方法的各种定义&#xff0c;包括参数和返回值&#xff0c;形象一点&#xff0c;我们说ArrayList和LinkedList从方法实现来说必须是等价的

为什么这么说呢&#xff1f;因为我们自己的类继承了这个接口&#xff0c;就必须覆盖掉接口中声明的函数&#xff08;可以理解为为方法加实体&#xff09;&#xff0c;而这个函数的定义必须和接口中的声明相同&#xff0c;换句话说&#xff0c;接口中声明的函数的spec你都必须以这个为标准去设计你的函数&#xff0c;因而我们说一个接口派生出来的n多个类都必须等价。

用三张图来解释操作&#xff1a;
图一&#xff1a;
图一
图二&#xff1a;
图2
图三&#xff1a;
图3
图一为接口数据类型&#xff0c;我之中定义了抽象方法&#xff08;无实体有声明&#xff09;。
图二为实现该接口的具体的类&#xff0c;implements关键字表示实施。
图三左图为我在具体的类中实现的接口中定义方法的实例&#xff0c;&#64;override关键字表示覆盖掉原有方法。

懂了这些起码在操作上不会有什么问题了。


2.抽象数据类型&#xff08;Abstract Data Type&#xff09;

好了&#xff0c;现在了解了什么是接口之后&#xff0c;我们来进入我今天的主题&#xff0c;ADT&#xff08;抽象数据类型&#xff09;&#xff0c;有了它&#xff0c;我们的编程将不再局限于既定的基本数据类型&#xff08;如int String等等&#xff09;和 对象数据类型&#xff08;ArrayList&#xff0c;LinkedList等等&#xff09;&#xff0c;而是可以自己创造出适合自己设计程序的数据类型。

有关数据的抽象&#xff0c;我们说是一组以操作刻画的数据类型&#xff0c;并不关心其内部的具体实现&#xff0c;只是我们能用它干什么&#xff0c;为什么用它成了关键。关于抽象类型&#xff0c;我们将不关心它的内部实现&#xff0c;而是如何使用它定义的操作成了我们的关心。

同样通过List 接口来说明&#xff1a;
在这里插入图片描述
查了一下java8&#xff0c;jdk的文档&#xff0c;找到了一个这样的解释&#xff0c;其中你会看到 这样的一种结构&#xff0c;你可以叫它泛型&#xff0c;这个什么意思呢&#xff0c;就是你可以定义任何一种类型去替换它&#xff08;包括String&#xff0c;int&#xff0c;或者是你自定义的一些类&#xff09;&#xff0c;然而并不会改变它内部功能的实现&#xff0c;想想是不是很容易理解但是想不明白怎么实现的&#xff1f;但是目前你只要知道这个泛型给这个接口的调用带来了很多的可能&#xff0c;这有时间在讨论。

言归正传&#xff0c;我们说一个抽象数据类型是并不关心它内部的实现的&#xff0c;因而作为定义方法却没有方法体的接口成为了首要说明对象
在这里插入图片描述
剖析接口中的方法我们可以看到&#xff0c;所有的方法都有其独特的说明&#xff08;在spec中声明出来的&#xff09;&#xff0c;仔细看他定义的方法&#xff0c;可以看到完全是基于数据层面上的n多操作。

仔细想想&#xff0c;有很多时候我们在程序定义一个现有的对象是为了应用它之中定义的API&#xff0c;甚至我们会直接调用某一个类中定义的某一个方法而不需要去实例化一个类别。这个时候我们就是客户&#xff0c;我们只关心它能为我们实现什么功能&#xff0c;而不关心它怎么实现的。因而我们说一个抽象数据类型的关键就在于它是“基于数据的操作”。


3.ADT的构成

ADT中的抽象方法的构成主要有四个方面&#xff1a;构造器&#xff08;Creators&#xff09;&#xff0c;生产器&#xff08;Producers&#xff09;&#xff0c;观察器&#xff08;Observers&#xff09;&#xff0c;变值器&#xff08;Mutators&#xff09;。

首先&#xff0c;构造器&#xff0c;顾名思义&#xff0c;创建一个新的对象&#xff0c;这是每一个类中所必需的&#xff0c;即便说你没有定义一个构造器在你的类中&#xff0c;其实编译器也隐含的创建了一个参数为空的构造器给你。

再者&#xff0c;生产器&#xff0c;实现从原有的数据类型中派生出一个新的数据类型出来&#xff0c;不难理解&#xff0c;我们说String这个数据类型是不可变&#xff08;immutable&#xff09;的&#xff0c;因而在我们对其进行某些字符串分割比如subString&#xff08;&#xff09;等操作的时候&#xff0c;就会产生一个新的和原来不一样的String类型变量出来&#xff0c;能够完成这种操作的方法我们叫它生产器。

其次&#xff0c;观察器&#xff0c;你可以形象的理解为这是对一个对象的现有状态的观察方法。举一个小例子&#xff0c;size&#xff08;&#xff09;函数&#xff0c;能够返回你定义的容器类型对象的现有大小&#xff0c;而不对其相应的值和各种参数做任何的改变。

最后&#xff0c;变值器&#xff0c;这和观察器是两种不同的概念&#xff0c;变值器的操作在于改变对象&#xff0c;可以有意识地改变对象的任何属性&#xff0c;比如add&#xff08;&#xff09;&#xff0c;向容器中加入一个对象&#xff0c;整个容器的尺寸加一&#xff0c;内容变化。

注意&#xff1a;一个可变数据类型&#xff08;mutable&#xff09;中一定会有变值器&#xff0c;而定义一个ADT是immutable的关键就在于&#xff0c;其内部定义的任何方法都不能改变他的表示不变量&#xff08;rep invariablity&#xff09;


4.ADT的设计

设计一组抽象数据类型&#xff0c;就要求我们提供一组操作&#xff0c;并规定其行为规约&#xff08;spec&#xff0c;详见主人博客规约设计&#xff09;。

首先&#xff0c;需要我们设计一组简单一致的操作。繁杂的操作可能会给用户带来极其糟糕的体验&#xff0c;以至于生命周期不长&#xff0c;而一组简单的操作&#xff0c;附上明确清晰的说明&#xff0c;会给用户一种不同的体验。一组API操作的简单与否可能与用户的数量息息相关。

其次&#xff0c;你的操作必须是有意义的&#xff0c;比如我们不能再List接口中定义有关求和的方法&#xff0c;因为那是针对于int&#xff0c;float类型数据才有意义的类型&#xff0c; 而诸如String等的类型则不适用&#xff0c;也因而失去了定义这个方法的意义。

再者&#xff0c;你的操作必须满足client对数据所需要做的所有操作需要&#xff0c;同时针对客户来说使用起来方便永远是设计ADT的第一原则。

最后&#xff0c;我们要分清具体和抽象的不同&#xff0c;你的设计要么基于抽象&#xff0c;要么基于具体应用。因为针对于不同的设计理念&#xff0c;作为开发者需要考虑的方面会有差异&#xff0c;同时也会改变相应的操作结构&#xff0c;因而如果分不清具体和抽象是会踩坑的。


5.有关编程


  • 表示独立性&#xff08;Representative Independence&#xff09;

  • spec契约

  • 测试优先编程&#xff08;Test-First Programming&#xff09;


推荐阅读
  • 异常要理解Java异常处理是如何工作的,需要掌握一下三种异常类型:检查性异常:最具代表性的检查性异常是用户错误或问题引起的异常ÿ ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 本文详细介绍了 iBatis.NET 中的 Iterate 元素,它用于遍历集合并重复生成每个项目的主体内容。通过该元素,可以实现类似于 foreach 的功能,尽管 iBatis.NET 并未直接提供 foreach 标签。 ... [详细]
  • 本文详细介绍了 org.apache.commons.io.IOCase 类中的 checkCompareTo() 方法,通过多个代码示例展示其在不同场景下的使用方法。 ... [详细]
  • 使用lambda表达式排序Collections.sort(temp,(Stringa,Stringb)-{returnb.compareTo(a);});Collections ... [详细]
  • 本文探讨了Java编程的核心要素,特别是其面向对象的特性,并详细介绍了Java虚拟机、类装载器体系结构、Java类文件和Java API等关键技术。这些技术使得Java成为一种功能强大且易于使用的编程语言。 ... [详细]
  • 对象自省自省在计算机编程领域里,是指在运行时判断一个对象的类型和能力。dir能够返回一个列表,列举了一个对象所拥有的属性和方法。my_list[ ... [详细]
  • Kubernetes 持久化存储与数据卷详解
    本文深入探讨 Kubernetes 中持久化存储的使用场景、PV/PVC/StorageClass 的基本操作及其实现原理,旨在帮助读者理解如何高效管理容器化应用的数据持久化需求。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • Java每日一题:876. 链表的中间节点解析
    本文详细介绍了LeetCode上编号为876的题目——链表的中间节点,包括问题描述、解决方案和代码实现。 ... [详细]
  • 本文介绍如何使用 Android 的 Canvas 和 View 组件创建一个简单的绘图板应用程序,支持触摸绘画和保存图片功能。 ... [详细]
  • 本文介绍了如何利用 Spring Boot 和 Groovy 构建一个灵活且可扩展的动态计算引擎,以满足钱包应用中类似余额宝功能的推广需求。我们将探讨不同的设计方案,并最终选择最适合的技术栈来实现这一目标。 ... [详细]
  • Python第三方库安装的多种途径及注意事项
    本文详细介绍了Python第三方库的几种常见安装方法,包括使用pip命令、集成开发环境(如Anaconda)以及手动文件安装,并提供了每种方法的具体操作步骤和适用场景。 ... [详细]
  • 解决Anaconda安装TensorFlow时遇到的TensorBoard版本问题
    本文介绍了在使用Anaconda安装TensorFlow时遇到的“Could not find a version that satisfies the requirement tensorboard”错误,并提供详细的解决方案,包括创建虚拟环境和配置PyCharm项目。 ... [详细]
  • 本文详细解析了Java中hashCode()和equals()方法的实现原理及其在哈希表结构中的应用,探讨了两者之间的关系及其实现时需要注意的问题。 ... [详细]
author-avatar
绿色小植被_552_584
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有