首页 > 代码库 > 《编程导论(Java)·4.1数据抽象的含义》

《编程导论(Java)·4.1数据抽象的含义》

You have no choice about the necessity to integrateyour observations,

your experiences, your knowledge into abstractideas, i.e., into principles.

——Ayn Rand, 《Philosophy: Who Needs It》 1974

数据抽象(Data abstraction)是将数据类型的抽象特征与事实上现的详细细节清晰地分离。

当中数据类型的“抽象特征”是指对用户代码而言可见的、怎样使用该数据类型的接口。数据抽象是接口与实现分离原则在类型层面以及对象技术中的推广

本章将介绍作为数据抽象的Java基本数据类型、抽象类、Java接口;重点讨论抽象类、接口的作用。

下一章继续介绍数据抽象——作为抽象数据类型的线性表及事实上现。


4.1数据抽象的含义

内存中保存的数值被称为数据或操作数,对数据进行分类是为了方便程序猿识别和操作它们。在[2.2.2 Java数据类型] 中,介绍了若干的概念:数据类型——定义一个值的集合以及处理这个值集的一组操作。Java语言的类型包含基本类型和程序猿自己定义的数据类型(引用类型)。

在[3.2.2 操作符]中,介绍了基本类型的各种操作;而在[2.4.1 引用的涵义]中列举了引用类型的7种操作。须要注意的是。上述全部的介绍均处于Java语言的层面[而非JVM层面]。

或者说,一直讨论的是Java数据类型的抽象特征——接口。


4.1.1 基本类型的实现

基本类型的接口/抽象特征包含该类型的取值范围和适用操作符。这里以最经常使用的int和boolean为例,说明数据抽象的含义。

1. int类型的接口和实现
    【这里先介绍int使用的一些注意事项】整数类型int是对数学整数的模拟。int与数学整数的区别在于int不是无限的。int类型逻辑上拥有32位内存空间,依照[0.1.2 二进制补码]。int类型的最大值(补码)为(231 -1)即2147483647或0x7FFF_FFFF,或二进制的0b01111111_11111111_11111111_11111111。当它加上1,就变成了0x8000_0000即最小值(-231即-2147483648)。

通常把整型的计算形容为在时钟的钟面上执行。计算时超过最大值或最小值的情况。称为溢出(O verflow与underflow),当使用大数字时。要小心溢出。由于没有不论什么人或异常机制帮助程序猿防止这样的程序错误的发生,它是一个沉默的杀手。

可用例如以下代码验证:
    void doSth(){
        int x=0x7FFFFFFF;
        System.out.println( x + 1 );
    }
此外,int中什么值能够使i == -i呢?除了零之外,还有最小值0x8000_0000。

因此if(i == -i)的语义不同于if(i == 0)。
对于int的操作。包含了大多数操作符,如算术、比較、位操作、赋值和一元操作的正负号、++、--等等。


    上述内容均为int的接口/抽象特征。作为int的用户,说int类型(逻辑上)拥有32位内存空间时。意味着用户知道了int的值域范围

其实。JVM规范中规定了int的值域范围,可是并未定义int类型的内存空间。用于储存int数据的内存空间,由JVM的不同实现者自由设定。

    通常,在JVM中使用字(word)作为数据值的基本尺寸单位。要求字的尺寸足够大,以保存byte, short, int, char, float, returnValue(Java程序猿不可用的一种JVM数据类型,用于实现Java程序中的finally子句)和reference。

而两个字足以装下long或double。普通情况下以主机平台的本地指针的尺寸为字的尺寸标准。

假设机器和系统平台是32位的,int值和全部引用(reference) 都被分配了32位内存;假设机器和系统平台是64位的,int值可能被分配了64位空间

通常int的用户并不关心int的实现,int的内存空间无论是32位还是64位,不得影响int的接口。即使系统用64位来保存int值,2147483647+1仍然会(也应该)表现为溢出(变成了最小值)。

练习4-1.:解释int类型的接口和实现的分离。

练习4-2.:编程typeSystem.primitive. IntDemo,验证溢出和i == -i。

 

2. boolean类型的接口和实现

    计算机会做的事情只是是算术操作和逻辑操作。因而布尔表达式在if-else语句、?:操作和循环语句中被广泛使用。关系操作符如5>2、x!=y等取值得到一个boolean值,布尔操作符如p && q进行逻辑运算。

不论什么一个非0的整数值x,表达式x!=0的值为true;不论什么一个非null的引用ref,表达式ref!=null的值为true。

   当人们眉开眼笑地讨论Java的布尔表达式、boolean类型时,其实讨论的是boolean接口。然而Java语言中如此重要和基础的boolean类型。并不实质性地存在。嗯,这个玩笑有点大。《JVM规范第2版》中有一节<3.3.4There Is No boolean Type>。其实JVM定义了boolean类型,可是没有提供操作boolean的指令。

《Java 虚拟机规范(Java SE 7 版)》的标题<2.3.4 boolean类型>更加严谨一些。

在JVM中。源码的boolean类型的运算被实现为JVM的int类型运算。

源码的boolean[]类型。其元素的訪问与改动使用JVM的byte类型数组的 baload 和 bastore 指令。

简单地说,boolean类型的实现。JVM定义了boolean这样的数据类型。如以"Z"或" [Z"分别表示boolean和boolean[]。也通过newarray 指令直接支持创建boolean[]。可是对boolean操作转换为int操作。1代表true、0代表false。而boolean[]视为byte数组操作。Sun的JVM实现将boolean[]元素作为8bit的值,其它JVM实现可能採用压缩形式。如一位。

int和boolean两个样例。反应了数据类型的抽象特征与事实上现的详细细节的差异。这就是将数据接口与实现加以清晰地分离的数据抽象的意义所在。

练习4-3:解释boolean类型在Java语言层面、JVM规范层面和JVM实现层面的不同,并由此解释抽象的价值。

4.1.2 类的接口

对于引用类型,不须要如同基本类型那样涉及到JVM。源码中没有对象。仅仅有引用变量和引用值。关于对象的实现參考[7.4.3堆上的对象]。类的接口与实如今[第6章封装]中详述,这里仅概要地说明。

1. 类的API

Parnas原则/接口与实现分离指在模块或方法层面,用户程序猿有意识地忽略方法的实现。而每个方法具有自己的接口。对于一个类A的用户而言,A所定义的(方法)接口唯独可以被訪问时才值得关注。很多方法——典型的如private方法,只被A自己使用,对外界而言,这些方法是否存在无关紧要也不得而知。因而在面向对象技术中,Parnas原则被推广到类层面。

类的接口指外界对象可以訪问的、类所定义的接口的集合。通常。类中声明的public、protected域,也作为类接口的一部分。

由上面的定义可知,随着客户程序与本类的关系的不同,如在或不在一个包中、是或不是本类的子类类的接口这一集合对客户类而言会有程度上的不同。使用訪问修饰符限定类的接口,这一机制称为封装,在[第6章封装]中具体介绍。

类的接口经常称为该类的API。这是为了与Java中的接口类型相差别。一般而言private和package-private方法不是类的接口。

 

2. 类和类型

绝大多数情况下,能够视class为一种type。比如,在[2.2.2Java数据类型]中所给出的(数据)类型的概念,将类作为类类型。

在[2.1.1里氏替换原则]中介绍了子类(subclass)与子类型(subtype)的差别。那么,类(class)和类型(type) 又有什么差异呢?

差异表如今接口与实现的分离上。type是一个名称,它标识了类的接口。

假设一个对象可以接受X类的接口的所有操作请求(方法调用),则称对象具有X类型

正是由于Java的子类可以满足父类的接口(虽然可以改写),所以子类的对象可以同一时候具有类层次中的多个类型

类(class)则是接口和实现的综合体。类不只定义了一种类型,也定义了对象的内部状态和方法的实现,以及不是接口的方法(如private方法)。简言之。类型是类的接口,类是类型+实现。

练习4-4.:一个对象能够有多个类型。

这些类型构成了一个____,如同生物学分类。

练习4-5:不同类的对象能够具有同样的类型,这个共同的类型被称为____ 。

练习4-6:子类继承父类的接口。请讨论这一命题。

练习4-7.:解释类(class)和类型(type)的差异。


技术分享


《编程导论(Java)&#183;4.1数据抽象的含义》