02_Java综述

面向对象编程

面向对象编程(Object-Oriented Programming,OOP)在Java中核心地位。几乎所有的Java程序至少在某种程度上都是面向对象的。OOP与java是密不可分的。下面说一下OOP的理论部分。

两种范式

​ 所有计算机程序都包含两种元素:代码和数据。而且从概念上讲,程序可以围绕代码或数据进行组织。也就是说,某些程序是围绕“正在发生什么”进行编写的,其他一些程序则是围绕“将影响谁”进行编写的。这是控制程序如何构造的两种范式。第一种方式被称为面向过程模型(process-oriented model)这种方式将程序描述为一系列线性步骤(即代码)。面向过程模型可以被认为是代码作用于数据。例如,C 这类过程化语言采用这种模型是相当成功的。但是,正如在第1章提到的,随着程序规模和复杂性的不断增长,这种方式带来的问题会逐渐显现出来。
​ 为了管理日益增长的复杂性,发明了
第二种方式,称为面向对象编程(object-oriented programming)
。面向对象编程围绕数据(即对象)以及一套为数据精心定义的接口组织程序**。面向对象编程的特点是数据控制对代码的访问。正如将会看到的,通过将数据作为控制实体,可以得到组织结构方面的诸多好处。

抽象

​ 面向对象编程的本质元素之一是抽象(abstraction)。人们通过抽象管理复杂性。例如,人们不会将一辆汽车想象成一系列相互独立的部分,而是将它想象成一个定义良好的具有自己独特行为的对象。通过这种抽象人们可以驾驶汽车到杂货店,而不会因为汽车零部件的复杂性而不知所措。人们可以忽略引擎、传动以及刹车系统的工作细节。相反,可以自由地作为一个整体使用这个对象。
​ 使用层次化分类是管理抽象的一种强有力方式。这种方式允许对复杂系统的语义进行分层,将它们分解为多个更易于管理的部分。从外部看,汽车是单个对象。而从内部看,汽车是由几个子系统构成的:驾驶系统、制动系统、音响系统、安全带、加热系统、移动电话,等等。如果继续细分,每个子系统是由更多特定的单元组成的。例如,音响系统是由收音机、CD 播放器和/或磁带或 MP3 播放器组成的。关键的一点是,通过层次化抽象管理汽车(或所有其他复杂系统)的复杂性。
复杂系统的层次化抽象也可以应用于计算机程序。来自传统面向过程程序的数据,通过抽象可以转换成程序的组件对象。程序中的一系列处理步骤,何以变成这些对象之间的消息集合。因此,每个对象描述了它自己的独特行为。可以将这些对象当作响应消息的具体实体,消息告诉对象做什么事情。这就是面向对象编程的本质。
面向对象的概念形成了 Java的核心,就如同它们形成了人类理解事物的基础一样。理解这些概念是如何被迁移到程序中的,这一点很重要。将会看到,对于创建在项目生命周期过程中不可避免地要发生变化的程序来说,面向对象编程是一种强大且自然的范式,所有比较大的软件项目都要经历如下生命周期:概念提出、成长和衰老。例如,如果具有定义良好的对象,并且这些对象的接口清晰可靠,那么就可以优美地废除或替换旧系统的某些部分,而不用担心发生问题。

OOP 三原则

​ 所有面向对象编程语言都提供了用于帮助实现面向对象模型的机制,这些机制是封装(encapsulation)、继承(inheritance)和多态(polymorphism)。现在让我们看一看这些概念。

封装

封装是将代码及其操作的数据绑定到一起的机制,并且保证代码和数据既不会受到外部干扰,也不会被误用。理解封装的一种方法是将它想象成一个保护性的包装盒,可以阻止在盒子外部定义的代码随意访问内部的代码和数据。对盒子内代码和数据的访问是通过精心定义的接口严格控制的。为了将封装联系到现实世界,考虑汽车上的自动传动装置,其中封装了引擎的数百位信息,例如当前的加速度、路面的坡度以及目前的挡位等。作为用户,您只有一个方法可以影响这个复杂的封装:换挡。例如,不能通过使用转弯信号或雨刷器来影响传动。因此,挡位是定义良好的(实际上也是唯一的)传动系统接口。此外,在传动系统内部发生的操作不会影响到外部对象。例如,挡位不会开启前灯!因为自动传动装置被封装了起来,所以任何一家汽车制造商都可以选择他们喜欢的方式实现它。但是,从驾驶员的角度看,它们的作用是相同的。相同的思想可以应用于编程。封装代码的优点是每个人都知道如何访问,因此可以随意访问而不必考虑实现细节,也不必担心会带来意外的负面影响。
​ 在Java中,封装的基础是类类(class)定义了一组对象共享的结构和行为(数据和代码)。给定类的每个对象都包含该类定义的结构和行为,就好像它们是从同一个类的模子中铸造出来的一样。由于这个原因,有时将对象称作类的实例(instance ofclass)。因此,类是一种逻辑结构,而对象是物理实体。
​ 当创建类时需要指定构成类的代码和数据。笼统地讲,这些元素称为类的成员(member)。特别地,类定义的数据被称为成员变量(member variable)或实例变量(instance variable)操作数据的代码称为成员方法(member method),或简称为方法(Java 程序员所说的方法,实际上就是CIC+程序员所说的函数,如果您熟悉 CIC++的话,了解这一点是有帮助的)。在正确编写的Java 程序中,方法定义了使用成员变量的方式。这意味着类的行为和接口是由操作实例数据的方法定义的。
​ 既然类的目的是封装复杂性,那么在类的内部就存在隐藏实现复杂性的机制类中的每个方法或变量可以被标识为私有的或公有的。类的公有(public)接口表示类的外部用户需要知道或可以知道的所有内容私有(private)方法和数据只能由类的成员代码访问所有不是类成员的其他代码都不能访问私有的方法或变量。因为只能通过类的公有方法访问类的私有成员,所以可以确保不会发生不正确的行为。当然,这意味着必须仔细地设计公有接口,不要过多地暴露类的内部工作情况。

继承

继承是一个对象获得另一个对象的属性的过程。继承很重要,因为它支持层次化分类的概念。在前面提到过,通过层次化分类(即从上向下),大多数知识都将可管理。例如,金毛猎犬是狗类的一部分,狗又是哺乳动物类的一部分,哺乳动物又是更大的动物类的一部分。如果不使用层次化分类,每个对象都将需要显式定义自身的所有特征。而通过使用继承对象只需要定义自己在所属类中独有的那些属性,可以从父类继承通用的属性。因此,继承机制使得对象成为更一般情况的特殊实例成为可能。下面进一步分析这个过程。
​ 大多数人很自然地将世界看作由各种以层次化方式相互关联的对象(例如动物、哺乳动物和狗)构成的。如果希望以抽象的方式描述动物,那么会说它们具有某些属性,例如体型、智力、骨骼系统的类型等。动物还具有特定的行为,它们需要进食、呼吸以及睡觉。对属性和行为的这一描述就是动物类的定义。
​ 如果希望描述更具体的动物类,例如哺乳动物,那么它们会有更特殊的属性,比如牙齿类型、乳腺类型等。这就是所谓的动物类的子类(subclass),而动物类被称作哺乳动物类的超类(superclass)。
​ 既然哺乳动物只不过是定义更加具体的动物,它们当然可以从动物类继承所有属性。深度继承的子类会继承整个类层次(class hierarchy)中每个祖先的所有属性。
继承还与封装相互作用。如果一个给定的类封装了某些属性,那么它的任何子类除了具有这些属性之外,还会添加自己特有的属性(见图2-2)。这是一个关键概念,它使面向对象程序的复杂性呈线性增长而非几何性增长。新的子类继承所有祖先的所有属性,它不会与系统中的大部分其他代码进行不可预料的交互。
在这里插入图片描述
在这里插入图片描述

多态

多态(来自希腊语,表示“多种形态”)是允许将一个接口用于一类通用动作的特性。具体使用哪个动作与应用场合有关。考虑堆栈(一种后进先出的数据结构),可能有一个程序需要三种类型的堆栈,一种用于整数值,另一种用于浮点值,第三种用于字符。尽管存储的数据不同,但是实现每种堆栈的算法是相同的。如果使用非面向对象的语言,需要创建三套不同的堆栈例程,每套例程使用不同的名称。但是,由于支持多态,因此使用 Java 可以指定一套通用的堆栈例程,所有这些例程共享相同的名称。
​ 更一般的情况是,多态的概念经常被表达为“一个接口,多种方法”。这意味着可以为一组相关的动作设计一个通用接口。多态允许使用相同的接口指定通用类动作(general class of action),从而有助于降低复杂性。选择应用于每种情形的特定动作(即方法)是编译器的任务,程序员不需要手动进行选择,只需要记住并使用通用接口即可。
​ 再次以狗作为例子,狗的嗅觉是多态的“如果狗闻到猫的气味,就会吠叫并且追着猫跑;如果狗闻到了食物的气味,就会分泌睡液并跑向盛着食物的碗。在这两种情况下,是相同的嗅觉在工作,区别是闻到的气味,也就是作用于狗鼻子的数据的类型!当将多态应用于 Java 程序中的方法时,也可以采用相同的通用概念来实现。

多态、封装与继承协同工作

​ 如果应用得当,由多态、封装和继承联合组成的编程环境面向过程模型环境相比,能支持开发更健壮、扩展性更好的程序。精心设计的类层次结构是重用代码的基础,在这个过程中,需要投入时间和精力进行开发和测试。通过封装可以随着时间迁移您的实现,而不会破坏那些依赖于类的公有接口的代码。通过多态可以创建出清晰、易懂、可读和灵活的代码
​ 对于前面两个真实的例子,汽车更全面地演示了面向对象设计的功能。狗的例子对于思考继承则很有趣,但是汽车更像程序。依靠继承,所有驾驶员能够驾驶不同类型的车辆(子类)。不管是校车、奔驰、保时捷,还是家用货车,驾驶员大体上都能找到并操作方向盘、制动闸和油门踏板。经过一段时间的腾合,大部分人甚至能够知道手动挡与自动挡之间的差别,因为他们从根本上理解了手动挡与自动挡的共同超类——传动。
人们总是与已经封装好的汽车特性进行交互。刹车和油门踏板隐藏了不可思议的复杂性,但是接口却非常简单,使用脚就可以操作它们。而引擎的实现、制动踏板的样式以及轮胎的大小,对于如何与踏板的类定义进行交互则没有影响。
​ 汽车制造商为基本相同的车辆提供多种选项的能力,清晰地反映了最后一个特性——多态。例如,刹车系统有正锁和反锁之分,方向盘有带助力和不带助力之分,引擎有 4 缸、6缸或8缸之分。不管采用哪种方式,仍然是通过踩下刹车踏板停车、转动方向盘改变方向、踩下油门踏板开动车辆。相同的接口可以用于控制大量不同的实现。
​ 可以看出,正是通过应用封装、继承和多态,将各个独立的部分变换成了所谓的汽车对象。对于计算机程序也一样。通过应用面向对象原则,可以将复杂系统的各个部分组合到一起,形成健壮、可维护的整体。
​ 在本节开头提到过,每个 Java 程序都是面向对象的。或者更准确地说,每个 Java 程序都涉及封装、继承和多态。将会看到,Java 提供的大部分特性都是内置类库的一部分,这些类库大量使用了封装、继承和多态。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值