对象
用引用操作对象
每种编程语言都有自己的操纵内存中元素的方式。有时候,程序员必须注意将要处理的数据是什么类型。你是直接操纵元素。还是用某种语法操纵元素。
在Java中一切都被视为对象,因此可以使用一种固定的语法来操纵元素。虽然一切都被视为对象但实际操作的是对象的一个引用(reference)。可以将这一情形想象成遥控(引用)来操纵电视机(对象),只要保持电视与遥控的链接,不管你需要对电视进行什么操作,实际上都是操作的遥控器,而你也可以在屋中四处走动同时仍能操作电视,而你只需要携带一个遥控,而不是电视。
此外,即使没有电视遥控器仍然能独立存在,也就是说你可以拥有一个引用,并不一定需要有一个对象与他相关联。
例如 String s;
这里只是创建了一个引用,并不是对象,如果此时向s发送一个消息(调用方法),就会返回一个运行时错误,这是因为s实际上没有与任何事物相关联(即,没有电视)。因此一种安全的做法是:创建一个引用的同时便初始化。
String s=”asdf”;
这里用到了一个Java语言的一个特性:字符串可以用带引号的文本初始化。而通常必须对对象采用一种更通用的初始化方法(new);
必须由你创建所有对象
一但引用被创建,就会希望他能与一个对象相关联。通常用new操作符来实现这一目的。new 关键字的意思是“给我一个新对象”。
String s=new String(“asdf”);
他不仅表示“给我一个新的字符串”,而且通过提供一个初始字符串,给出了怎样产生这个String的信息。
对象被储存到什么地方
程序运行时,对象是怎么安排放置的的?内存又是怎样分配的?有五个不同的地方可以储存数据:
1, 寄存器:这是最快的的存储区,它位于处理器内部,但是寄存器的数量极其有限,所以寄存器根据需求进行分配。你不能直接控制,也不能在程序中感觉到寄存器的存在。
2, 堆栈:位于通用RAM(随机访问存储器)中,但通过堆栈指针可以从处理器哪里获得直接支持。堆栈指针若是向下移动,则分配新的内存;若向上移动,则删除那些内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时,Java系统必须知道存储在战队内所有项目多的确切生命周期,以便上下移动堆栈指针。这一约束限制了程序的灵活性,所以虽然某些Java数据存储在堆栈中----特别是对象引用。但是Java对象并不存储于其中。
3, 堆:一种通用的内存池(也位于RAM区),用于存放所有的Java对象。堆不同于堆栈的好处是:编译器不需要知道存储的数据在堆里存活多上时间。因此,在堆里分配存储有很大的灵活性。当需要一个对象时,只需要用new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。但是这种灵活性必须要付出代价:用堆进行存储分配和清理可能比用栈进行存储分配需要更多的时间。
4, 常量存储:常量值通常直接存储在程序代码内部,这样做是安全的,因为它们永远不会被改变。有时,在嵌入式系统中,常量本身会和其他部分隔离开,所以在这种情况下,可以选择将其放在ROM只读存储器中。
5, 非RAM存储:如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行的时候也可以存在。其中两个基本的例子是流对象和持久化对象。在流对象中,对象转化成字节流,通常被发给另一台机器。在“持久化对象”中,对象被存放在硬盘中。因此即便程序终止它们仍可以保持自己的状态。
基本类型
在程序中有一系列经常用到的类型,它们需要特殊对待,因为new将对象存储在“堆”里,故用 new创建一个对象,特别是简单的很小的对象,往往不是很有效率。因此对于这些对象Java把他们称之为基本类型,它们不需要new来创建,而是创建一个并非是引用的“自动”变量。这个变量直接存储“值”,并置于堆栈中,因此更加高效。
Java要确定每种基本类型所占存储空间的大小。正是这种占存储空间大小不变性是Java程序比用其他大多数语言编写的程序更具可移植性的原因之一。
基本类型 大小 最小值 最大值 包装容器类型
boolean - - - Boolean
char 16-bit Unicode 0 Unicode 2(16)-1 Character
byte 9 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
括号内数字代表乘方
所有数值类型都有正负号。
boolean类型所占存储空间的大小没有明确指定,仅定义为能够取字面值true或false.
基本数值都有其包装类,使得可以在堆中创建一个基本对象,用来表示基本数据类型
char x=’c’;
Character ch=new Character(‘x’);
Java SE5能自动的将基本类转化为包装类
Character ch=’x’;
也可反向操作
char x=ch;
高精度数字
Java中提供了两个用于高精度计算的类:BigInteger和BigDecimal,这两种包装类是不存在基本类型与其对应的。
这两个包装类提供的方法与基本类型所能执行的操作相似,也就是说可以执行类似int,float的操作。用调用方法的方式来取代运算符运算来实现,这么做运算速度会比较慢,而相对的精度会提高。
BigInteger支持任意精度的整数,也就是说运算中可以表示任何大小的整数值而不会丢失
BigDecimal则支持任何精度的定点数,例如可以进行精确的货币计算。
不需要销毁对象
大多数程序设计语句需要程序员时刻监视变量,销毁变量。而Java却可以帮助我们完成所有清理工作
作用域
大多数过程语言都有作用域(scope)的概念。作用域决定了在其内定义的变量名的可见性和生命周期,在Java中,作用域由花括号位置决定例如
{
int x=12;
//只能使用x
{
int q=96;
//x和q都可以使用
}
//只可以使用x
//q的作用域外
}
在作用域里定义的变量只可用于作用域结束之前
缩排格式使Java代码更易阅读。由于Java是一种自由格式(free-form)的语言,所以,空格,制表符,换行都不会影响程序的执行结果。
Java中不允许这样的语法
{
int x=12;
{
int x=96;
}
}
编译器将会报告x已经被定义过。
对象的作用域
Java对象不具备和基本数据类型一样的生命周期,当用new创建一个对象的时候,他可以存活于作用域之外。
{
String s=new String(“a string”);
//作用域终点
}
引用s在作用域终点就消失了。然而,s指向的String对象仍继续占据内存空间。在这一段小代码中,我们无法在这个作用于之后访问这个对象,因为对他唯一的引用已经超出作用域范围。但实际在程序的执行中,是可以传递和复制对象引用的
所以实际上,由new创建出的对象,只要你需要就会一直保留下去。那么Java又是靠什么才能防止这些对象填满内存空间呢?Java特有一个垃圾回收机制(GC),用来监视用new创建的所有对象,并辨别哪些不再被引用的对象。随后便释放这些内存空间。