前言
《Thinking in Java》做为Java最经典的学习书籍之一,不论是对于学习java的新手或是有一定经验的程序员来说都有不同的学习价值,在工作的这两年多当中由于种种杂事一直没时间拜读此书,近期决定坚持每天抽空细读一下,一方面巩固一下java基础,另一方面要找一下学习的状态,每天忙于项目不停赶进度写代码而忽略了学习也是不行的,所以感觉通过写blog来坚持读书学习也是很不错的,本系列blog参照的是《Java编程思想第4版》,第一章“对象导论”简要介绍了Java语言的一些重要特性和知识点,我们从第二章“一切都是对象”开始记录。
用引用操纵对象
如题,这一小节介绍了编程语言操纵内存中元素的方式,包括:
- 直接操纵——Java中的引用(reference)
- 间接操纵——C&C++中的指针(pointer)
和C以及C++相比,这些在Java中得到了简化,因为一切都被视为对象,而操纵对象的标识符也就是对象的一个引用(reference)了。例如:
String s;
这样就创建了一个String对象的引用——s,注意此时并没有对象被创建。作者建议更安全的做法是创建引用的同时初始化对象,例如:
String s = "asdf";
这里展示了一个Java语言的特性:字符串可以用带引号的文本初始化。
必须由你创建所有对象
这里提到了创建对象的通用方式——new关键字。new关键字的意思是“给我一个新对象”,上面的例子同样可以这样写:
String s = new String("asdf");
尽管这些显而易见,我们很清楚String类提供了这样的一个构造方法,但作者必然是按照循序渐进的思路去介绍知识点,所以跟上作者的思路来继续看下去。
存储到什么地方
这里介绍了部分硬件相关的知识点,即:对象在内存中是怎样放置和存储?下面提到了5个可以存储数据的地方:
- 寄存器。
在学习计算机基础时我们都知道寄存器位于CPU(中央处理器)中,而且它是最快的存储区,但是寄存器的数量有限,它是根据需求自动分配,Java语言无法控制。 - 堆栈。
位于RAM(随机访问存储器),其速度仅次于寄存器,堆栈指针向下移动,则分配新内存;若向上移动,则释放那些内存。某些Java数据会存储于堆栈中,特别是对象的引用,但这里强调了Java对象并不会存储在这里。 - 堆。
也位于RAM区,是一种通用的内存池,用于存放所有Java对象。在堆中分配存储相较于堆栈更具灵活性,但代价是效率会低于堆栈。 - 常量存储。
常量值通常直接存放在程序代码内部,它们永远不会被改变。在嵌入式操作系统中,可以选择放在ROM(只读存储器)中。 - 非RAM存储。
分为流对象和持久化对象,即不受程序的任何控制。流对象就是将对象转换为字节流进行传输,而持久化对象也就是常用的将对象存储在数据库中了,例如在Java中常用的JDBC和Hibernate。
特例:基本类型
在Java中基本类型不用通过new关键字来创建(同C&C++一致),而是通过直接声明的方式去创建,例如:
char c = 'x';
这里的c是一个并非是引用的“自动变量”,这个变量直接存储“值”,并置于堆栈中,因此更加高效。简单总结一下:
- 创建基本类型无需new关键字,这一点和C以及C++一致。
- 基本类型创建后并无引用(reference),它应视为一个“自动”变量,并直接将值存储在堆栈中(普通对象均存储在堆中)。
Java要确定每种基本类型所占存储空间的大小(不像其它大多数语言随机器硬件架构变化而变化,这也是更具可移植性的原因之一)。
下面看一下Java中所有基本类型的大小范围:
基本类型 | 大小 | 最小值 | 最大值 | 包装器类型 |
---|---|---|---|---|
boolean | - | - | - | Boolean |
char | 16-bit | Unicode 0 | Unicode 2^16-1 | Character |
byte | 8 bits | -128 | +127 | Byte |
short | 16 bits | -2^15 | +2^15-1 | Short |
int | 32 bits | -2^31 | +2^31-1 | Integer |
long | 64 bits | -2^63 | +2^63-1 | Long |
float | 32 bits | IEEE754 | IEEE754 | Float |
double | 64 bits | IEEE754 | IEEE754 | Double |
void | - | - | - | Void |
在Java中所有数值类型都有正负号(而C语言中有无符号类型unsigned)。
另外,基本类型也提供了包装器对象(Wrapper),它和普通对象一样在堆中被创建,每一种包装器都对应一个基本类型。例如:
Character ch = new Character('x');
关于包装器在后面的章节再细说,但显而易见的一点是,和普通类型相比它的效率会低一些(存储堆栈和堆的区别),但同时这种代价会允许它做更多的事情。
Java中还提供了两个用于高精度计算的类:BigInteger 和 BigDecimal:
- BigInteger支持任意精度的整数运算。
- BigDecimal支持任意浮点数运算(例如货币运算)。
Java中的数组
这里仅仅强调了Java数组的安全性(和C&C++做对比),即:Java确保数组会被初始化,而且不能在它的范围之外被访问。基本类型的数组初始化由编译器来保证(将数组所占的内存全部置零),对象数组则是相当于创建了一个引用数组,且每个引用都会初始化为null,若试图使用null引用则会报运行时异常,因此常见的数组错误在Java中可以避免。
永远不要销毁对象
作用域
大多数过程性语言都有作用域概念(scope),在Java和C&C++中,作用域均是由花括号的位置决定的,例如:
{
int x = 12;
// Only x available
{
int q = 96;
// Both x & q available
}
// Only x available
// q is