第二章:一切都是对象
创建句柄
在创建句柄(references)时如果没有初始化,往往会发生错误,如String s;
,因此更安全的做法是在创建句柄的时候进行初始化,String s = "abcd";
在创建新的句柄时,String s = new String("abcd");
new的意思也就是创建一个新的对象,这条语句不仅仅是创建了一个字符串,而且包含了怎样生成这个字符串的信息。
java的存储方式
Java有5种存储方式:寄存器,堆栈,堆,静态存储,常数存储,非RAM式存储。
寄存器: 最快的存储方式,不同于其他方式,它是直接存储在CPU里面的,但是由于空间非常小,所以要根据需要分配,我们对此没有直接的控制权,在程序中也无法看到。
栈: 通常是在RAM中,但是通过堆栈指针,可以直接与CPU通信,是一种非常有效且快速的分配方式,指针下移创建内存空间,指针上移释放内存空间。但是由于分配方式灵活性的限制,并不是所有的数据都存储在堆栈中,所以当创建对象时,在堆栈中的只是对象的句柄(references)对象本身并不在堆栈中。
堆:是一种常规用途的内存池(也在RAM中),其中保存的是JAVA对象,编译器并不知道要分配多少内存空间,在堆里停留多久。当需要一个新的对象时,只需要一个
new
,当这条语句执行时,就会自动在堆中分配空间。静态存储:这儿的“静态”(Static)是指“位于固定位置”(尽管也在RAM里)。程序运行期间,静态存储的数据将随时等候调用。可用static关键字指出一个对象的特定元素是静态的。但Java对象本身永远都不会置入静态存储空间。
常数存储: 常数通常直接置入代码内部,这样是安全的,因为他们永远都不会改变。为了安全考虑,在嵌入式设备中,它们通常是被置入ROM中。
非RAM存储: 这类数据可以在程序没有运行的时候存在,主要分为两种,流式对象和固定对象,流式对象会变成字节流,发给另外一台机器。而固定对象保存在磁盘中。这些类型的数据可以再需要的时候将它们变成存在于RAM中的对象。
特殊情况:主数据类型 primitive types
Java中采用了与c/c++相同的方法,不用new变量,而是创建一个并非句柄的“自动”变量。这些数据存储在堆栈中。
Primitive type | Size | Minimum | Maximum | WapperType |
---|---|---|---|---|
boolean | 1-bit | - | - | Boolean |
byte | 8-bit | -128 | +127 | Byte[1] |
short | 16-bit | -2^15 | +2^15–1 | Short[1] |
int | 32-bit | -2^31 | +2^31–1 | Integer |
long | 64-bit | -2^63 | +2^63–1 | Long |
float | 32-bit | IEEE754 | IEEE754 | Float |
double | 64-bit | IEEE754 | IEEE754 | Double |
void | – | – | – | Void[1] |
作用域
在C,C++和JAVA里,作用域是由花括号的位置决定的。
1 | { |
注意尽管在C和C++里是合法的,但在Java里不能象下面这样书写代码:
1 | { |
编译器会认为变量x已被定义。
对象的作用域
JAVA中对象和主数据类型有不一样的存在时间,如下
1 | { |
句柄s会在作用域的终点消失,而句柄s指向的对象仍在内存中占用着空间,对此,java引入了垃圾收集器的机制,会查找出不再被引用的对象,释放这些对象占据的内存。
类
类是自己定义的数据类型,当你定义一个类的时候,可以向类中设置两种类型的元素:成员变量(field)和方法(method)
static关键字
不需要创建对象就可以调用静态的方法或者或者数据,由于static方法不需要创建任何对象,所以不能简单地调用其他那些成员。
例如,下述代码能生成一个static数据成员,并对其初始化:
1 | class StaticTest { |
现在new了两个StaticTest的对象,但他们的值都是47,因为他们引用同一片内存区域。当 i
变化时, st1.i
, st2.i
都会同时变化。
静态方法的定义类似
1 | class StaticFun { |
由于是静态方法,可以直接调用 incr()
StaticFun.incr();
也可以用典型的方法调用 incr()
1 | StaticFun sf = new StaticFun(); |