Java编程思想-第2章 一切皆对象(要点)

“如果我们说另一种不同的语言,那么我们就会发觉一个有些不同的世界。”

                 Luduing Wittgenstein(1889-1951)

  尽管Java是基于C++的,但是相比之下,Java是一种更“纯粹”的面向对象程序设计语言 C++和Java都是混合/杂合型语言。但是,Java的设计者认为这种杂合性并不像在C++中那么 重要。杂合型语言允许多种编程风格;C++之所以成为一种杂合型语言主要是因为它支持与C语 言的向后兼容。因为C++是C的一个超集,所以势必包括许多C语言不具备的特性,这些特性使 C++在某些方面显得过于复杂。 Java语言假设我们]只进行面向对象的程序设计。也就是说,在开始用Java进行设计之前,必 须将思想转换到面向对象的世界中来。这个入门基本功,可以使你具备使用这样一种编程语言 编程的能力,这种语言学习起来更简单,也比许多其他OOP语言更易用。在本章,我们将看到 Java程序的基本组成部分,并体会到在Java中(几乎)一切都是对象。

2.1 用引用操纵对象

  每种编程语言都有自己的操纵内存中元素的方式。有时候,程序员必须注意将要处理的数 据是什么类型。你是直接操纵元素,还是用某种基于特殊语法的间接表示(例如C和C+里的指 针)来操纵对象? 所有这一切在Java里都得到了简化。一切都被视为对象,因此可采用单一固定的语法。尽 管一切都看作对象,但操纵的标识符实际上是对象的一个“引用”( reference)e。可以将这 情形想像成用遥控器(引用)来操纵电视机(对象)。只要握住这个遥控器,就能保持与电视机 的连接。当有人想改变频道或者减小音量时,实际操控的是遥控器(引「用),再由遥控器来调控 电视机(对象)。如果想在房间里四处走走,同时仍能调控电视机,那么只需携带遥控器(引用) 而不是电视机(对象)。

2.2 必须由你创建所有对象

   一旦创建了一个引「用,就希望它能与一个新的对象相关联。通常用new操作符来实现这一目 的。new关键字的意思是“给我一个新对象。”所以前面的例子可以写成: String s new String("asdf") 它不仅表示“给我一个新的字符串”,而且通过提供一个初始字符串,给出了怎样产生这个 Sting的信息。 当然,除了 String类型,Java提供了大量过剩的现成类型。重要的是,你可以自行创建类型 事实上,这是Java程序设计中一项基本行为,你会在本书以后章节中慢慢学到。

2.2.1 存储到什么地方

  程序运行时,对象是怎么进行放置安排的呢?特别是内存是怎样分配的呢?对这些方面的 了解会对你有很大的帮助。有五个不同的地方可以存储数据:

1)寄存器。这是最快的存储区,因为它位于不同于其他存储区的地方—处理器内部。但 是寄存器的数量极其有限,所以寄存器根据需求进行分配。你不能直接控制,也不能在程序中 感觉到寄存器存在的任何迹象(另一方面,C和C++允许您向编译器建议寄存器的分配方式)。

2)堆栈。位于通用RAM(随机访问存储器)中,但通过堆栈指针可以从处理器那里获得直 接支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些内存。这是一种快 速有效的分配存储方法,仅次于寄存器。创建程序时,Java系统必须知道存储在堆栈内所有项 的确切生命周期,以便上下移动堆栈指针。这一约束限制了程序的灵活性,所以虽然某些Java 数据存储于堆栈中—特别是对象引用,但是Java对象并不存储于其中

3)堆。一种通用的内存池(也位于RAM区),用于存放所有的Java对象。堆不同于堆栈的好 处是:编译器不需要知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵 活性。当需要一个对象时,只需用new写一行简单的代码,当执行这行代码时,会自动在堆里进 行存储分配。当然,为这种灵活性必须要付出相应的代价:用堆进行存储分配和清理可能比用 堆栈进行存储分配需要更多的时间(如果确实可以在Java中像在C++中一样在栈中创建对象)。

4)常量存储。常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会 被改变。有时,在嵌入式系统中,常量本身会和其他部分隔离开,所以在这种情况下,可以选 择将其存放在ROM(只读存储器)中。

5)非RAM存储。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序 没有运行时也可以存在。其中两个基本的例子是流对象和持久化对象。在流对象中,对象转化 成字节流,通常被发送给另一台机器。在“持久化对象”中,对象被存放于磁盘上,因此,即 使程序终止,它们仍可以保持自己的状态。

这种存储方式的技巧在于:把对象转化成可以存放 在其他媒介上的事物,在需要时,可恢复成常规的、基于RAM的对象。Java提供了对轻量级持 久化的支持,而诸如JDBC和 Hibernate这样的机制提供了更加复杂的对在数据库中存储和读取对象信息的支持。

2.2.2 特例:基本类型

   在程序设计中经常用到一系列类型,它们需要特殊对待。可以把它亻们想像成“基本”类型。 之所以特殊对待,是因为new将对象存储在“堆”里,故用new创建一个对象—特别是小的、 简单的变量,往往不是很有效。因此,对于这些类型,Java采取与C和C++相同的方法。也就是 说,不用new来创建变量,而是创建一个并非是引用的“自动”变量。这个变量直接存储“值”, 并置于堆栈中,因此更加高效 Java要确定每种基本类型所占存储空间的大小。它们的大小并不像其他大多数语言那样随 机器硬件架构的变化而变化。这种所占存储空间大小的不变性是Java程序比用其他大多数语言 编写的程序更具可移植性的原因之一。

2.2.3 Java中的数组

  几乎所有的程序设计语言都支持数组。在C和C++中使用数组是很危险的,因为C和C++中 的数组就是内存块。如果一个程序要访问其自身内存块之外的数组,或在数组初始化前使用内 存(程序中常见的错误),都会产生难以预米料的后果。 Java的主要目标之一是安全性,所以许多在C和C++里困扰程序员的问题在Java里不会再出 现。Java确保数组会被初始化,而且不能在它的范围之外被访问。这种范围检查,是以每个数 组上少量的内存开销及运行时于的下标检查为代价的。但由此换来的是安全性和效率的提高,因 此付出的代价是值得的(并且Java有时可以优化这些操作)。 当创建一个数组对象时,实际上就是创建了一个引用数组,并且每个引用都会自动被初始 化为一个特定值,该值拥有自己的关键字nul。一旦Java看到nul,就知道这个引用还没有指向 某个对象。在使用任何引|用前,必须为其指定一个对象;如果试图使用一个还是nu的引「用,在 运行时将会报错。因此,常犯的数组错误在Java中就可以避免。

2.3 永远不需要销毁对象

  在大多数程序设计语言中,变量生命周期的概念,占据了程序设计工作中非常重要的部分 变量需要存活多长时间?如果想要销毁对象,那什么时刻进行呢?变量生命周期的混乱往往会 导致大量的程序bug,本节将介绍Java是怎样替我们完成所有的清理工作,从而大大地简化这个问题的。

2.3.1 作用域

大多数过程型语言都有作用域( scope)的概念。作用域决定了在其内定义的变量名的可见 性和生命周期。在C、C++和Java中,作用域由花括号的位置决定。

例如:

{

   int x =12

   // Only x available 

   {  

     int q= 96  

    //Both x & g available  

  }  

  // q is " out of scope  

  // Only x available

}

在作用域里定义的变量只可用于作用域结束之前。

2.3.2 对象的作用域

  Java对象不具备和基本类型一样的生命周期。当用new创建一个Java对象时,它可以存活于 作用域之外。所以假如你采用代码 String s= new String ("a string") 引用s在作用域终点就消失了。然而,s指向的 String对象仍继续占据内存空间。在这一小段代码 中,我们无法在这个作用域之后访问这个对象,因为对它唯一的引用已超出了作用域的范围。 在后继章节中,读者将会看到:在程序执行过程中,怎样传递和复制对象引用。

2.4 创建新的数据类型:类

  如果一切都是对象,那么是什么决定了某一类对象的外观与行为呢?换句话说,是什么确 定了对象的类型?你可能期望有一个名为“type”的关键字,当然它必须还要有相应的含义。然 而,从历史发展角度来看,大多数面向对象的程序设计语言习惯用关键字clas来表示“我准备 告诉你一种新类型的对象看起来像什么样子”。 classi这个关键字(以后会频繁使用,本书以后就 不再用粗体字表示)之后紧跟着的是新类型的名称。例如:

class Atypename i /* Class body goes here */

这就引入了一种新的类型,尽管类主体仅包含一条注释语句(星号和斜杠以及其中的内容就是 注释,本章后面再讨论)。因此,你还不能用它做太多的事情。然而,你已经可以用new来创建 这种类型的对象

Atypename a = new Atypename()

但是,在定义它的所有方法之前,还没有办法能让它去做更多的事情(也就是说,不能向它发 送任何有意义的消息)。

2.4.1 字段和方法

  旦定义了一个类(在Java中你所做的全部工作就是定义类,产生那些类的对象,以及发 送消息给这些对象),就可以在类中设置两种类型的元素:字段(有时被称作数据成员)和方法 (有时被称作成员函数)。字段可以是任何类型的对象,可以通过其引用与其进行通信;也可以 是基本类型中的一种。如果字段是对某个对象的引用,那么必须初始化该引「用,以便使其与 个实际的对象(如前所述,使用new来实现)相关联。

2.5 方法、参数和返回值

  许多程序设计语言(像C和C+)用函数这个术语来描述命名子程序;而在Java里却常用方 法这个术语来表示“做某些事情的方式”。实际上,继续把它看作是函数也无妨。尽管这只是用 词上的差别,但本书将沿用Java的惯用法,即用术语“方法”而不是“函数”来描述。 ava的方法决定了一个对象能够接收什么样的消息。方法的基本组成部分包括:名称、参 数、返回值和方法体。下面是它最基本的形式

ReturnType methodName( / *Argument list */ ){ / *Method body */ }  

2.5.1 参数列表

  方法的参数列表指定要传递给方法什么样的信息。正如你可能料想的那样,这些信息像 Java中的其他信息一样,采用的都是对象形式。因此,在参数列表中必须指定每个所传递对象 的类型及名字。像Java中任何传递对象的场合一样,这里传递的实际上也是引用,并且引用的 类型必须正确。如果参数被设为 String类型,则必须传递一个 String对象;否则,编译器将抛出 错误。

2.8.4 一些标签示例

这里将介绍一些可用于代码文档的 javadoc标签。在使用 javadoc0处理重要事情之前,应该先 到JDK文档那里查阅 javadoc参考,以学习 javadoc的各种不同的使用方法

1.@see:引用其他类 @see标签允许用户引|用其他类的文档。 javadoc会在其生成的HTML文件中,通过@see标签 链接到其他文档。格式如下:

@see classname

@see fully-qualified-classname

@see fully-qualified-classname#me thod-name

2.10 总结

通过本章的学习,大家已接触相当多的关于如何编写一个简单程序的Java编程知识。此外, 对ava语言及它的一些基本思想也有了一个总体认识。然而到目前为止,所有示例都是“这样 做,再那样做,接着再做另一些事情”这种形式。如果想让程序做出选择,例如,“假如所做的 结果是红色,就那样做;否则,就做另一些事情”。这将又怎样进行呢?Java对此种基本编程行 为所提供的支持,将会在下一章讲述。

posted @ 2018-02-28 14:41  JackYgy  阅读(117)  评论(0)    收藏  举报