Java Review (六、面向对象----类和对象)

  • this关键字

    • 类的导入

面向对象

======================================================================

在目前的软件开发领域有两种主流的开发方法:结构化开发方法面向对象开发方法。早期的编程 语言如C、Basic、Pascal等都是结构化编程语言;随着软件开发技术的逐渐发展,人们发现面向对象可 以提供更好的可重用性、可扩展性和可维护性,于是催生了大量的面向对象的编程语言,如Java、 C#和 Ruby 等。

结构化开发方法概述


结构化程序设计方法主张按功能来分析系统需求,其主要原则可概括为自顶向下、逐步求精、模块化等。结构化程序设计首先采用结构化分析(Structured Analysis, SA)方法对系统进行需求分析,然后使用结构化设计(Structured Design, SD)方法对系统进行概要设计、详细设计,最后釆用结构化编 程(Structured Program, SP)方法来实现系统。使用这种SA、SD和SP的方式可以较好地保证软件系 统的开发进度和质量。

因为结构化程序设计方法主张按功能把软件系统逐步细分,因此这种方法也被称为面向功能的程序设计方法;结构化程序设计的每个功能都负责对数据进行一次处理,每个功能都接受一些数据,处理完后输出一些数据,这种处理方式也被称为面向数据流的处理方式。

结构化程序设计里最小的程序单元是函数,每个函数都负责完成一个功能,用以接收一些输入数据, 函数对这些输入数据进行处理,处理结束后输出一些数据。整个软件系统由一个个函数组成,其中作为 程序入口的函数被称为主函数,主函数依次调用其他普通函数,普通函数之间依次调用,从而完成整个软件系统的功能。

结构化软件的逻辑结构示意图

在这里插入图片描述

从图中可以看出,结构化设计需要采用自顶向下的设计方式,在设计阶段就需要考虑每个模块应该 分解成哪些子模块,每个子模块又分解成哪些更小的模块……依此类推,直至将模块细化成一个个函数。

每个函数都是具有输入、输出的子系统,函数的输入数据包括函数形参、全局变量和常量等,函数的输出数据包括函数返回值以及传出参数等。结构化程序设计方式有如下两个局限性。

  • 设计不够直观,与人类习惯思维不一致。釆用结构化程序分析、设计时,开发者需要将客观世 界模型分解成一个个功能,每个功能用以完成一定的数据处理。

  • 适应性差,可扩展性不强。由于结构化设计采用自顶向下的设计方式,所以当用户的需求发生 改变,或需要修改现有的实现方式时,都需要自顶向下地修改模块结构,这种方式的维护成本 相当高。

采用结构化方式设计的软件系统,整个软件系统就由一个个函数组成,这个软件的运行入口往往由一个“主函数”代表,而主函数负责把系统中的所有函数“串起来”。

面向对象程序设计简介


面向对象是一种更优秀的程序设计方法,它的基本思想是使用对象继承封装消息等基本概念进行程序设计。它从现实世界中客观存在的事物(即对象)出发来构造软件系统,并在系统构造中尽可能运用人类的自然思维方式,强调直接以现实世界中的事物(即对象)为中心来思考,认识问题, 并根据这些事物的本质特点,把它们抽象地表示为系统中的类,作为系统的基本构成单元(而不是用一 些与现实世界中的事物相关比较远,并且没有对应关系的过程来构造系统),这使得软件系统的组件可 以直接映像到客观世界,并保持客观世界中事物及其相互关系的本来面貌。

面向对象方式开发的软件的逻辑结构示意图

在这里插入图片描述

从图中看出,面向对象的软件系统由多个类组成,类代表了客观世界中具有某种特征的一类事物,比如汽车,汽车内部存在一些状态数据(Field),比如颜色、款式。

面向对象的语言不仅使用类来封装一类事物的内部状态数据,这种状态数据就对应于图中的Field(成员变量),而且类会提供操作这些状态数据的方法,还会为这类事物的行为特征提供相应的实现,这种实现也是方法。因此可以得到如下基本等式:

成员变量(状态数据)+方法(行为)=类定义

从这个等式来看,面向对象比面向过程的编程粒度要大:面向对象的程序单位是类;而面向过程的程序单位是函数(相当于方法),因此面向对象比面向过程更简单、易用。

>

面向过程与面向对象对比

在这里插入图片描述

假设需要组装一台电脑,如果拿到手的是主板、CPU、内存条、硬盘等这种大粒度的组件,可以很轻松地组装成一台电脑;但如果拿到手的是一些二极管、三极管、 集成电路等小粒度的组件,要想把它们组装成电脑,就不简单了。如果把数据以及操j 作数据的方法都封装成对象,这就相当于提供了大粒度的组件,因此编程更容易。

从面向对象的眼光,开发者希望从自然的认识、使用角度来定义和使用类。也就是说,开发者希望直接对客观世界进行模拟:

  • 定义一个类,对应客观世界的某种事物

  • 业务需要关心这个事物的哪些状态, 程序就为这些状态定义成员变量

  • 业务需要关心这个事物的哪些行为,程序就为这些行为定义方法

不仅如此,面向对象程序设计与人类习惯的思维方法有较好的一致性,比如希望完成“猪八戒吃西瓜”:

在面向过程的程序世界里,一切以函数为中心,函数最大,因此这件事情会用如下语句来表达:

吃(猪八戒,西瓜);

在面向对象的程序世界里,一切以对象为中心,对象最大,因此这件事情会用如下语句来表达:

猪八戒.吃(西瓜);

对比两条语句不难发现,面向对象的语句更接近自然语言的语法:主语、谓语、宾语一目了然,十 分直观,因此程序员更易理解。

面向对象基本特征


面向对象方法具有三个基本特征: 封装 (Encapsulation)、 **继承(Inheritance)**和 多态(Polymorphism)

封装指的是将对象的实现细节隐藏起来,然后通过一些公用方法来暴露该对象的功能;

继承是面向向对象实现软件复用的重要手段,当子类继承父类后,子类作为一种特殊的父类,将直接获得父类的属性和方法;

多态指的是子类对象可以直接赋给父类变量,但运行时依然表现岀子类的行为特征,这意味着 同一个类型的对象在执行同一个方法时,可能表现出多种行为特征。

除此之外,抽象也是面向对象的重要部分,抽象就是忽略一个主题中与当前目标无关的那些方面, 以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是考虑部分问题。例如, 需要考察Person对象时,不可能在程序中把Person的所有细节都定义出来,通常只能定义Person的部 分数据、部分行为特征——而这些数据、行为特征是软件系统所关心的部分。

虽然抽象是面向对象的重要部分,但它不是面向对象的特征之一,因为所有的编程语都需要抽象.当开发者进行抽象时应该考虑哪些特征是软件系统所需要的,那么这些特征就应该使用程序记录并表现出来。因此,需要抽象哪些特征没有必然的规定,而是取决于软件系统的功能需求。

===================================================================

类( class) 是对某种事物的抽象,是构造对象的模板或蓝图。我们可以将类想象成月饼模具,将对象想象为月饼。由类构造(construct) 对象的过程称为创建类的实例 (instance )。

定义类


语法:

[修饰符]class类名{

零个到多个构造器定义…

零个到多个成员变量

零个到多个方法…

}

说明:

  • 修饰符可以是public, final、abstract,或者完全省略这三个修饰符

  • 类名理论上只要是一个合法的标识符即可,但从程序的可读性方面来看,Java 类名必须是由一个或多个有意义的单词连缀而成的,每个单词首字母大写,其他字母全部小写,单词与 单词之间不要使用任何分隔符

  • 三种最常见的成员:构造器、成员变量和方法,三种成员都可以定义零个或多个,如果三种成员都只定义零个,就是定义了一个空类,这没有太大的实际意义。

一个类实例

public class Dog{

//成员变量

String breed;

private int age;

String color;

//方法

void barking(){

}

public void hungry(){

}

private void sleeping(){

}

}

类型变量

一个类可以包含以下类型变量:

  • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。

  • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。

  • 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。

static是一个特殊的关键字,它可用于修饰方法、成员变量等成员。static修饰的成员表明它属于这个类本身,而不属于该类的单个实例,因为通常把static修饰的成员变量和方法也称为类变量类方法。 不使用static修饰的普通方法、成员变量则属于该类的单个实例,而不属于该类。因为通常把不使用static 修饰的成员变量和方法也称为实例变量、实例方法。

由于static的英文直译就是静态的意思,因此有时也把static修饰的成员变量和方法称为静态变量静态方法,把不使用static修饰的成员变量和方法称为非静态变量和非静态方法。静态成员不能直接访问非静态成员。

提示:虽然绝大部分资料都喜欢把static称为静态,但实际上这种说法很模糊,完全无法说明static的真正作用。static的真正作用就是用于区分成员变量、方法、内部类、初始化块

构造方法

每个类都有构造方法。如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。

在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。

构造方法实例

public class Puppy{

//无参构造方法

public Puppy(){

}

//有参构造方法

public Puppy(String name){

// 这个构造器有一个参数:name

}

}

对象

====================================================================

对象是类的一个实例。

对象的三个主要特性:

  • 对象的行为(behavior)—可以对对象施加哪些操作,或可以对对象施加哪些方法

  • 对象的状态(state )—当施加那些方法时,对象如何响应

  • 对象标识(identity )—如何辨别具有相同行为与状态的不同对象

创建对象


对象是根据类创建的。在Java中,使用关键字new来创建一个新的对象。创建对象需要以下三步:

  • 声明:声明一个对象,包括对象名称和对象类型。

  • 实例化:使用关键字new来创建一个对象。

  • 初始化:使用new创建对象时,会调用构造方法初始化对象

创建对象实例

public class Puppy{

public Puppy(String name){

//这个构造器仅有一个参数:name

System.out.println("小狗的名字是 : " + name );

}

public static void main(String[] args){

// 下面的语句将创建一个Puppy对象

Puppy myPuppy = new Puppy( “tommy” );

}

}

访问实例变量和方法


实例

public class Puppy{

int age;

String name;

public Puppy(String name){

// 这个构造器有一个参数:name

this.name=name;

System.out.println("小狗的名字是 : " + name );

}

//无参构造方法

public Puppy(){

}

public void setAge( int age ){

this.age = age;

}

public int getAge( ){

System.out.println("小狗的年龄为 : " + puppyAge );

return puppyAge;

}

public static void main(String[] args){

/* 创建对象 */

Puppy myPuppy = new Puppy( “tommy” );

/* 通过方法来设定age */

myPuppy.setAge( 2 );

/* 调用另一个方法获取age */

myPuppy.getAge( );

/*可以像下面这样访问成员变量 */

System.out.println("变量值 : " + myPuppy.puppyAge );

}

}

对象、引用和指针


创建对象语句:

Puppy p = new Puppy( “tommy” );

在这行代码中实际产生了两个东西:一个是p变量, 一个是Puppy对象。

从Puppy类定义来看,Puppy对象应包含1个实例变量,而变量是需要内存来存储的。因此,当创建Puppy对象时,必然需要有对应的内存来存储Puppy对象的实例变量。

Puppy对象内存存储示意图

在这里插入图片描述

从图中可以看出,Puppy对象由多块内存组成,不同内存块分别存储了 Puppy对象的不同成员变量。当把这个Puppy对象赋值给一个引用变量时,系统如何处理呢?难道系统会把这个Puppy对象 在内存里重新复制一份吗?显然不会,Java没有这么笨,Java让引用变量指向这个对象即可。也就是说,引用变量里存放的仅仅是一个引用,它指向实际的对象。

与前面介绍的数组类型类似,类也是一种引用数据类型,因此程序中定义的Puppy类型的变量实 际上是一个引用,它被存放在栈(stack)内存里,指向实际的Puppy对象;而真正的Puppy对象则存放在堆(heap) 内存中。图5.2显示了将Person对象赋给一个引用变量的示意图。

引用变量指向实际变量示意图示意图

在这里插入图片描述

栈内存里的引用变量并未真正存储对象的成员变量,对象的成员变量数据实际存放在堆内存里;而引用变量只是指向该堆内存里的对象。从这个角度来看,引用变量与C语言里的指针很像,它们都是存储一个地址值,通过这个地址来引用到实际对象。实际上,Java里的引用就是C里的指针,只是Java 语言把这个指针封装起来,避免开发者进行烦琐的指针操作。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值