当前位置: 首页 > news >正文

《thinking in Java》--第二章一切都是对象

  1:尽管将一切都“看作” 对象,但操纵的标识符实际是指向一个对象的“句柄”(Handle)。在其他 Java 参考书里,还可看到有的人将其称作一个“引用”,甚至一个“指针”。可将这一 情形想象成用遥控板(句柄)操纵电视机(对象)。只要握住这个遥控板,就相 当于掌握了与电视机连接的通道。但一旦需要“换频道”或者“关小声音”,我 们实际操纵的是遥控板(句柄),再由遥控板自己操纵电视机(对象)。如果要在 房间里四处走走,并想保持对电视机的控制,那么手上拿着的是遥控板,而非电 视机。

此外,即使没有电视机,遥控板亦可独立存在。也就是说,只是由于拥有一 个句柄,并不表示必须有一个对象同它连接。所以如果想容纳一个词或句子,可 创建一个 String 句柄:                    String s;

但这里创建的只是句柄,并不是对象。若此时向 s 发送一条消息,就会获得 一个错误(运行期)。这是由于 s 实际并未与任何东西连接(即“没有电视机” )。 因此,一种更安全的做法是:创建一个句柄时,记住无论如何都进行初始化:                

String s = "asdf";

然而,这里采用的是一种特殊类型:字串可用加引号的文字初始化。通常, 必须为对象使用一种更通用的初始化类型。  

创建句柄时,我们希望它同一个新对象连接。通常用 new 关键字达到这一目 的。new 的意思是:“把我变成这些对象的一种新类型”。所以在上面的例子中, 可以说:

String s = new String("asdf");

它不仅指出“将我变成一个新字串”,也通过提供一个初始字串,指出了“如何生成这个心字符串"

 

  2:保存到什么地方

程序运行时,我们最好对数据保存到什么地方做到心中有数。特别要注意的 是内存的分配。有六个地方都可以保存数据:

(1) 寄存器。这是最快的保存区域,因为它位于和其他所有保存方式不同的 地方:处理器内部。然而,寄存器的数量十分有限,所以寄存器是根据需要由编 译器分配。我们对此没有直接的控制权,也不可能在自己的程序里找到寄存器存 在的任何踪迹。

(2) 堆栈。驻留于常规 RAM(随机访问存储器)区域,但可通过它的“堆栈 指针”获得处理的直接支持。堆栈指针若向下移,会创建新的内存;若向上移, 则会释放那些内存。这是一种特别快、特别有效的数据保存方式,仅次于寄存器。 创建程序时,Java 编译器必须准确地知道堆栈内保存的所有数据的“长度”以 及“存在时间”。这是由于它必须生成相应的代码,以便向上和向下移动指针。 这一限制无疑影响了程序的灵活性,所以尽管有些 Java 数据要保存在堆栈里— —特别是对象句柄,但 Java 对象并不放到其中。

(3) 堆。一种常规用途的内存池(也在 RAM 区域),其中保存了 Java 对象。 和堆栈不同,“内存堆”或“堆”(Heap)最吸引人的地方在于编译器不必知道 要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间。 因此,用堆保存数据时会得到更大的灵活性。要求创建一个对象时,只需用 new 命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。当 然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉 更长的时间!

(4) 静态存储。这儿的“静态”(Static)是指“位于固定位置”(尽管也在 RAM 里)。程序运行期间,静态存储的数据将随时等候调用。可用 static 关键字 指出一个对象的特定元素是静态的。但 Java 对象本身永远都不会置入静态存储 空间。

(5) 常数存储。常数值通常直接置于程序代码内部。这样做是安全的,因为 它们永远都不会改变。有的常数需要严格地保护,所以可考虑将它们置入只读存 储器(ROM)。

(6) 非 RAM 存储。若数据完全独立于一个程序之外,则程序不运行时仍可 存在,并在程序的控制范围之外。其中两个最主要的例子便是“流式对象”和“固 定对象”。对于流式对象,对象会变成字节流,通常会发给另一台机器。而对于 固定对象,对象保存在磁盘中。即使程序中止运行,它们仍可保持自己的状态不 变。对于这些类型的数据存储,一个特别有用的技巧就是它们能存在于其他媒体 中。一旦需要,甚至能将它们恢复成普通的、基于 RAM 的对象。Java 1.1 提供 了对 Lightweight persistence 的支持。未来的版本甚至可能提供更完整的方案

特殊情况:主要类型 有一系列类需特别对待;可将它们想象成“基本”、“主要”或者“主” (Primitive)类型,进行程序设计时要频繁用到它们。之所以要特别对待,是由
于用 new 创建对象(特别是小的、简单的变量)并不是非常有效,因为 new 将 对象置于“堆”里。所以对于这些主要类型,Java 采纳了与 C 和 C++相同的方法。也就 是说,不是用 new 创建变量,而是创建一个并非句柄的“自动”变量。这个变 量容纳了具体的值,并置于堆栈中,能够更高效地存取。 Java 决定了每种主要类型的大小。就象在大多数语言里那样,这些大小并 不随着机器结构的变化而变化。这种大小的不可更改正是 Java 程序具有很强移 植能力的原因之一。

主类型 大小 最小值 最大值 封装器类型
boolean 1 位 - - Boolean

char 16 位 Unicode 0 Unicode 2 的 16 次方-1 Character

byte 8 位 -128 +127 Byte(注释①)

short 16 位 -2的 15 次方 +2的 15 次方-1 Short(注释①) i

nt 32 位 -2的 31 次方 +2的 31 次方-1 Integer

long 64 位 -2的 63 次方 +2的 63 次方-1 Long

float 32 位 IEEE754 IEEE754 Float

double 64 位 IEEE754 IEEE754 Double

 高精度数字

Java 1.1 增加了两个类,用于进行高精度的计算:BigInteger 和 BigDecimal。 尽管它们大致可以划分为“封装器”类型,但两者都没有对应的“主类型”。 这两个类都有自己特殊的“方法”,对应于我们针对主类型执行的操作。也 就是说,能对 int 或 float 做的事情,对 BigInteger 和 BigDecimal 一样可以做。 只是必须使用方法调用,不能使用运算符。此外,由于牵涉更多,所以运算速度 会慢一些。我们牺牲了速度,但换来了精度。

BigInteger 支持任意精度的整数。也就是说,我们可精确表示任意大小的整 数值,同时在运算过程中不会丢失任何信息。

BigDecimal 支持任意精度的定点数字。例如,可用它进行精确的币值计算。

至于调用这两个类时可选用的构建器和方法,请自行参考联机帮助文档。  

 

 

 

  7: Java 的数组 

在 C++里,应尽量不要使用数组,换用标准模板库(Standard TemplateLibrary)里更安全的容器。 

而一个 Java 可以保证被初始化,而且不可在它的范 围之外访问。由于系统自动进行范围检查,所以必然要付出一些代价:针对每个 数组,以及在运行期间对索引的校验,都会造成少量的内存开销。但由此换回的 是更高的安全性,以及更高的工作效率。为此付出少许代价是值得的。

创建对象数组时,实际创建的是一个句柄数组。而且每个句柄都会自动初始 化成一个特殊值,并带有自己的关键字:null(空)。一旦 Java 看到 null,就知 道该句柄并未指向一个对象。正式使用前,必须为每个句柄都分配一个对象。若 试图使用依然为 null 的一个句柄,就会在运行期报告问题。因此,典型的数组错 误在 Java 里就得到了避免。 也可以创建主类型数组。同样地,编译器能够担保对它的初始化,因为会将 那个数组的内存划分成零。 

  

  8:作用域

对于在作用域里 定义的名字,作用域同时决定了它的“可见性”以及“存在时间”。在 C,C++ 和 Java 里,作用域是由花括号的位置决定的

 {

            int x = 12;

            /* only x available */

             {

                int q = 96;

                /* both x & q available */

             }

             /* only x available */

             /* q “out of scope” */

}  

注意尽管在 C 和 C++里是合法的,但在 Java 里不能象下面这样书写代码:

   {

               int x = 12;

               {

                  int x = 96; /* illegal */

               }

 }  

编译器会认为变量 x 已被定义。所以 C 和 C++能将一个变量“隐藏”在一 个更大的作用域里。但这种做法在 Java 里是不允许的,因为 Java 的设计者认 为这样做使程序产生了混淆。 

 

 对象的作用域 

Java 对象不具备与主类型一样的存在时间。用 new 关键字创建一个 Java 对象的时候,它会超出作用域的范围之外  

{

String s = new String("a string");

} /* 作用域的终点 */

那么句柄 s 会在作用域的终点处消失。然而,s 指向的 String 对象依然占据 着内存空间。在上面这段代码里,我们没有办法访问对象,因为指向它的唯一一 个句柄已超出了作用域的边界。在后面的章节里,大家还会继续学习如何在程序 运行期间传递和复制对象句柄。 

 

  9:新建数据类型:类

定义一个类时(我们在 Java 里的全部工作就是定义类、制作那些类的对象 以及将消息发给那些对象),可在自己的类里设置两种类型的元素:数据成员(有 时也叫“字段”)以及成员函数(通常叫“方法”)。其中,数据成员是一种对象 (通过它的句柄与其通信),可以为任何类型。它也可以是主类型(并不是句柄) 之一

  10:主成员的默认值 

若某个主数据类型属于一个类成员,那么即使不明确(显式)进行初始化, 也可以保证它们获得一个默认值。
主类型 默认值
Boolean false

Char '\u0000'(null)

byte (byte)0

short (short)0

int 0

long 0L

float 0.0f

double 0.0d

一旦将变量作为类成员使用,就要特别注意由 Java 分配的默认值。这样做 可保证主类型的成员变量肯定得到了初始化(C++不具备这一功能),可有效遏 止多种相关的编程错误。 然而,这种保证却并不适用于“局部”变量——那些变量并非一个类的字段。 

所以,假若在一个函数定义中写入下述代码:

int x;

那么 x 会得到一些随机值(这与 C 和 C++是一样的),不会自动初始化成零。 我们责任是在正式使用 x 前分配一个适当的值。如果忘记,就会得到一条编译期 错误,告诉我们变量可能尚未初始化。这种处理正是 Java 优于 C++的表现之一。 许多 C++编译器会对变量未初始化发出警告,但在 Java 里却是错误。  

 

  11: 方法、自变量和返回值

迄今为止,我们一直用“函数”(Function)这个词指代一个已命名的子例程。 但在 Java 里,更常用的一个词却是“方法”(Method),代表“完成某事的途径”。 尽管它们表达的实际是同一个意思,但从现在开始,本书将一直使用“方法”, 而不是“函数”。

Java 的“方法”决定了一个对象能够接收的消息。

Java 的方法只能作为类的一部分创建。只能针对某个对象调用一个方法(正如马上就要学到的那样,“静态”方法可针对类调用,毋需一个对象)

int x = a.f(); 

象这样调用一个方法的行动通常叫作“向对象发送一条消息”。在上面的例 子中,消息是 f(),而对象是 a。面向对象的程序设计通常简单地归纳为“向对象 发送消息”。 

 

正如在 Java 其他地方处理对象时一样,我们实际传递的是“句柄”(注释④)。

④:对于前面提及的“特殊”数据类型 boolean,char,byte,short,int, long,,float 以及 double 来说是一个例外。但在传递对象时,通常都是指传递指 向对象的句柄。 

 

  12:使用其他组件

用 import 关键字准确告诉 Java 编译器我们希望的类是什么。import 的作用是 指示编译器导入一个“包”——或者说一个“类库”(在其他语言里,可将“库” 想象成一系列函数、数据以及类的集合。但请记住,Java 的所有代码都必须写 入一个类中)。 

import java.util.Vector;

它的作用是告诉编译器我们想使用 Java 的 Vector 类。然而,util 包含了数 量众多的类,我们有时希望使用其中的几个,同时不想全部明确地声明它们。为 达到这个目的,可使用“*”通配符。如下所示:

import java.util.*;

需导入一系列类时,采用的通常是这个办法。应尽量避免一个一个地导入类

 

  13 static 关键字

通常,我们创建类时会指出那个类的对象的外观与行为。除非用 new 创建那 个类的一个对象,否则实际上并未得到任何东西。只有执行了 new 后,才会正 式生成数据存储空间,并可使用相应的方法。

但在两种特殊的情形下,上述方法并不堪用。一种情形是只想用一个存储区 域来保存一个特定的数据——无论要创建多少个对象,甚至根本不创建对象。另 一种情形是我们需要一个特殊的方法,它没有与这个类的任何对象关联。也就是 说,即使没有创建对象,也需要一个能调用的方法。为满足这两方面的要求,可 使用 static(静态)关键字。一旦将什么东西设为 static,数据或方法就不会同 那个类的任何对象实例联系到一起

当然,在正式使用前,由于static 方法不需要创建任何对象,所以它们不可简单地调用其他那些成员,同时不引用 一个已命名的对象,从而直接访问非 static 成员或方法(因为非 static 成员和方 法必须同一个特定的对象关联到一起)。

 

**尽管是“静态”的,但只要应用于一个数据成员,就会明确改变数据的创建 方式(一个类一个成员,以及每个对象一个非静态成员)。若应用于一个方法, 就没有那么戏剧化了。对方法来说,static 一项重要的用途就是帮助我们在不必 创建对象的前提下调用那个方法。正如以后会看到的那样,这一点是至关重要的 ——特别是在定义程序运行入口方法 main()的时候。 和其他任何方法一样,static 方法也能创建自己类型的命名对象。所以经常 把 static 方法作为一个“领头羊”使用,用它生成一系列自己类型的“实例”。  

 

转载于:https://www.cnblogs.com/yanquan/p/7248933.html

相关文章:

  • C# 添加、修改和删除PDF书签
  • DIR
  • 《分布式系统:概念与设计》一2.4.2 故障模型
  • Airbnb 数据基础设施与其背后的哲学
  • 给Java开发者的10个大数据工具和框架
  • BOOM:一款有趣的Javascript动画效果
  • Spark的三种集群deploy模式对比
  • 国际网络安全攻防盛宴——SSCTF线上赛顺利收官
  • 不懂编程和数据库也能创建表单
  • 20年来首次:英特尔痛失全球市场桂冠,智能芯片王者争霸AI致胜
  • ASP.NET MVC Preview生命周期分析
  • ie9下浏览器 cosole.log()会阻止j下面的s加载
  • .NET Core引入性能分析引导优化
  • OneDrive 消费者版本全面缩减免费存储容量
  • Oracle 为什么必须收购 Salesforce?
  • .pyc 想到的一些问题
  • [译] React v16.8: 含有Hooks的版本
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • 10个确保微服务与容器安全的最佳实践
  • Angularjs之国际化
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • javascript 哈希表
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 前端相关框架总和
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (3)(3.5) 遥测无线电区域条例
  • (C语言)共用体union的用法举例
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (学习日记)2024.01.19
  • (转)人的集合论——移山之道
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .NET 常见的偏门问题
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .net流程开发平台的一些难点(1)
  • ::
  • [ Linux Audio 篇 ] 音频开发入门基础知识
  • [4.9福建四校联考]
  • [C puzzle book] types
  • [IE编程] 打开/关闭IE8的光标浏览模式(Caret Browsing)
  • [Java基础]—JDBC
  • [LeetCode]—Add Binary 两个字符串二进制相加
  • [NowCoder]牛客OI周赛3
  • [OCR]Python 3 下的文字识别CnOCR
  • [OGRE]看备注学编程(02):打地鼠01-布置场地九只地鼠