目录
一,面向对象概述
与传统程序设计区别
解决规模
二,类
概述
类的三大特性:
封装
继承
多态
三,对象
对象的三主要特性:
行为(behavior)
状态(state)
标识(identity)
四,创建类的思路
五,类之间关系
依赖
聚合
继承
面向对象程序设计(object-oriented programming, OOP)是目前主流的程序设计范型。它的出现代替了以前的基于面向过程的编程技术。
由于Java是基于面向对象设计的一门语言,所以想要学习Java,熟悉OOP是必不可少的。
面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。程序中的很多对象来自于标准库,但也有些是自定义的。要完成一门程序,两者都必不可少。
传统的面向过程程序设计通过一系列过程(即算法)来求解问题。一旦确定了这些过程,就要开始考虑存储数据的适当方式。这就是Pascal语言设计者要将他的著作命名为《算法+数据结构=程序》的原因了。
需要注意的是,算法是第一位,数据结构是第二位,这就明确了以前的程序设计方式:首先要确定如何操作数据,然后再考虑如何组织数据的结构。
而对于OOP来说,却调换了这个次序,采取了先将数据解决好,再考虑算法操作数据的事。
两者在在处理程序规模的问题上有区别:
对于一些小规模问题,采用基于面向过程的开发方式比较理想。因为面向对象需要搭架构,小规模问题需要搭架构就能解决,这时采用面向对象程序设计效率就低了。
而对于大规模问题,面向对象更加合适。例如想要实现一个Web浏览器可能需要2000个过程,采用面向对象只需要设计大约100个类,每个类包含20个左右方法就能解决。而且采用面向对象框架更清晰,类与类之间耦合低,更容易发现bug出现在哪里。
类(Class)是构造对象的模板或蓝图。我们可以想象成类是做甜甜圈的模具,而对象则是甜甜圈。由类构造对象的过程称之为创建类的实例。
基于Java编写的代码基本上都集中在类里。标准Java库提供了几千个类,可以用于各种目的,例如数字运算、字符串拼接、日期显示等等。但是在Java中还是需要自己创建一些类,以便描述你的应用程序所应对的问题领域中的对象。
封装(encapsulation)有时也称数据隐藏,是处理对象的一个重要概念。
从表面看,封装就是把数据和行为组合到一个类中,并对外只暴露它的功能,但隐藏具体的实现方式。相当于给调用类的对象赋予了“黑盒子”特征。
在类中:数据称之为属性,操作数据的过程称为方法。作为类的一个实例,特定对象都有特定的属性。这些值得集合就是当前对象的状态(state)。无论何时,只要在对象上调用一个方法,它的状态就可能发生改变。
实现封装的关键在于,绝对不能让类中的方法直接访问其它类的数据。程序只能通过对象方法和对象数据进行交互。封装给予对象“黑盒子”的特征,是提高重用性和可靠性的关键。在类里面完全可以改变数据存储方式,例如给数据加上static修饰,数据存储的位置就会移到元空间,但只要使用同样的方法操作数据,对象就不会知道也不用关心这个类发生的变化。
类的另一个特性能让Java看起来更简单,就是可以通过扩展其他类来构建新类,这称之为继承(inheritance)。在扩展一个类时,扩展出的新类继承被扩展的类的全部属性和方法。你只需要在新类中提供合适这个新类的新方法和新属性就够了。
事实上,在Java中所有的类,都继承于一个超级父类,它就是Object类。所有类都扩展自这个Object类。对于继承关系,被继承的称为父类,继承的称为子类。
关于继承的详细展开,会在后面文章提到。若看到这里对你有所帮助,请点赞关注观雨Java,笔者会在后续陆续更新文章。
类中有父类和子类之称,子类创建的对象,也是父类型的一种形态。这就是对象的多态性。
扩展:方法的重载和重写也是多态的一种,不过是方法的多态。可以理解为相同方法名称的多种形态。
多态在编程实操中体现在对对象的转型。由于对象存在多态性,所以可以进行转型操作。
而转型分为两种:
1,向上转型:将子类对象变为父类对象
2,向下转型:将父类对象传给子类对象
对象类型的转换可以理解为用已创建的对象实例对另一个类对象初始化。
由于父类可以包含多种子类,所以父类转型成子类需要范围限定。
需要注意的是:如果父类A有B、C两个子类,把B创建的对象初始化A后,不能再做初始化C。
想要使用OOP,首先也得弄清楚对象的三个主要特性:
同一类的所有对象实例,由于支持相同的行为而具有家族式的相似性。对象的行为是用可调用的方法来定义的。
每个对象都保存着描述当前状态的信息。这就是对象的状态。
对象状态可能会随着时间而发生改变,但这种改变不会是自发的。对象状态的改变必须通过调用方法实现(如调用set方法修改参数),如果不经过调用就可以改变对象状态,就说明封装性有问题。
每个对象都有一个唯一的标识(身份),你可以理解为对象指向的地址。即使行为状态都一样,标识不同,也是两个不同对象。注意的是,作为同一个类得实例,每个对象的标识总是不同的,状态也往往存在着差异。
对象这些关键特性会相互影响。
例如对象状态会影响它行为:如果一个订单“”已送货”,则不能要求“往订单增加商品”。相反,一个订单“正在添加商品”,则还不能“正在送货”。
传统的基于过程编程,就是想到哪写到哪,有所谓的开始部分。但基于面向对象程序设计没有所谓的“开始部分”,这会导致刚接触OOP不知道从哪里开始写程序。
有一个方法:从识别需要什么类开始,然后再为各类添加方法。
识别类的一个简单经验就是把问题从头到尾分析一遍,记录出现的名词和动词。
例如,在把大象装进冰箱这个过程中,有这样的名词:
有了这些名词,就新建相应的大象类,冰箱类。
有这样的动词:
下一步则是负责匹配动作和名词的关系:
识别出动作的对象是谁:例如打开冰箱,把大象运送到冰箱,关闭冰箱,这些动作的对象都是冰箱;打昏大象,这个动作的对象就是大象;
然后就该知道冰箱类里面要创建“打开方法”、“运送方法”、“关闭方法”;大象类里面要创建“打昏方法”。
当然这种动\名词原则只是一种经验,所以需要经常编写程序,经验才能更好帮到你。
在类之间,最常见的关系有:
依赖是一种最明显、常见的关系。最常见的依赖关系体现在某一个类里面的方法,需要传入的是另一个类的对象作为参数;所以如果一个类的方法使用或者操作另一个类的对象,我们救说一个类依赖于另一个类。
应该尽可能减少这种依赖关系,也就是减少类之间的耦合。因为没有依赖关系,A类的变化完全不用担心B类出bug。
聚合这种关系很具体,当A类中包含着B类,就称为聚合。有些人也习惯称为关联。通常定义整体类后,再去分析这个整体类中的组成结构,如果某些组成结构为成员类(另外的类),该整体类和成员类之间就形成聚合关系;
public class Subject{
private Math math;
......
}
public class Math{
......
}
表示了一个更特殊的类(子类)和一般的类(父类)之间的关系。
例如A类继承了B类,在跟更特殊了A类中除了包含B类的所有方法和属性,还可以扩展属于自己方法和属性。如果B类继承了C类,那么B类从C类继承和自己扩展的东西能全部继承给A类。
关于继承的详细展开,会在后面文章提到。若看到这里对你有所帮助,请点赞关注观雨Java,笔者会在后续陆续更新文章。