java 核心技术-12版 卷Ⅰ- 4.2.1 对象与对象变量
要想使用对象,首先必须构造对象,并指定其初始状态。然后对对象应用方法。
在Java设计语言中,要使用构造器(constructor或称构造函数)构造新实例。构造器是一种特殊的方法,其作用是构造并初始化对象。下面来看一个例子。标准Java库中包含一个Date类。它的对象可以描述一个时间点,例如“Decemeber 31,1999,23:59:59 GMT”。
注释:你可能会感到奇怪:为什么用类表示日期,而不是像其他语言中那样用一个内置(built-in)类型来表示?例如,Visual Basic中有一个内置的date 类型,程序员可以采用#12/31/1999#格式指定日期。看起来这似乎很方便,程序员只需要使用内置的date类型,而不用考虑类。但实际上,Visual Basic这样设计合适吗?在有些地区,日期表示为月/日/年 ,而另外一些地区则表示为 日/月/年。语言设计者是否能够遇见这些问题呢?如果没有处理好这类问题,语言就有可能陷入混乱,对此感到不满的程序员也会丧失使用这种语言的热情。如果使用类,这些设计任务就交给了类库的设计者。如果类设计得不完善,那么其他程序员可以很容易地编写自己的类,改进或替换(replace)这些系统类(作为印证:Java的日期类库开始时有些混乱,现在已经重新设计了两次)。
构造器总是与类同名。因此,Date类的构造器就名为Date。要想构造一个Date对象,需要在构造器前面加上new操作符,如下所示:
new Date();
这个表达式会构造一个新对象。这个对象初始化为当前的日期和时间。
如果需要的话,可以将这个对象传递给一个方法:
System.out.println(new Date());
或者,可以对刚构造的对象应用一个方法。Date类中有一个toString方法。这个方法将生成日期的一个字符串描述。可以如下对新构造的Date对象应用toString方法:
String s = new Date().toString();
在这个例子中,构造的对象仅使用了一次。通常,你可以希望保留所构造的对象从而能继续使用,为此,需要将对象放在一个变量中:
Date now = new Date();
图4-3显示了对象变量 now,它引用了新构造的对象。

对象与对象变量之间存在着一个重要的区别。例如,以下语句
Date startTime;// startTime doesn't refer to any Object
定义了一个对象变量 startTime,它可以引用Date类型的对象。但是,一定要认识到:变量startTime不是一个对象,而且实际上它甚至还没有引用任何对象。此时不能在这个变量上使用任何Date方法。下面的语句:
s= startTime.toString();//not yet
将产生编译错误。
必须首先初始化starTime变量,这里有两个选择。当然,可以初始化这个变量,让它引用一个新构造的对象:
startTime= new Date();
也可以设置这个变量,让它引用一个已有的对象:
startTime =now;
现在,这两个变量都引用同一个对象(如同4.4)

要认识到重要的一点:对象变量并不实际包含一个对象,它只是引用一个对象。
在Java中,任何对象变量的值都是一个引用,指向存储在另外一个地方的某个对象,new 操作符的返回值也是一个引用。下面的语句:
Date startTime = new Date();
有两个部分,表达式new Date() 构造了一个Date 类型的对象,它的值是新创建对象的一个引用。再将这个引用存储在 startTime变量中。
可以显式将对象变量设置为null,指示这个对象变量目前没有引用任何对象。
startTime = null;
...
if(startTime != null)
System.out.println(startTime);
我们将在4.3.6节更相信地讨论null。
C++注释: 很多人错误地认为Java中的对象变量就相当于C++中的引用。然而,C++中没有null引用,而且引用不能赋值。应当把Java中的对象变量看做类似于C++的对象指针。例如,Date now;// java
实际上等同于
Date* now;// C++
一旦建立了这种关联,一切就清楚了。当然,只有使用了new 调用后 Date* 指针才会初始化。就这一点而言,C++与Java的语法几乎是一样的。
Date* now = new Date();// C++
如果把一个变量复制到另一个变量,两个变量就指向同一个日期,即它们是同一个对象的指针。Java中的 null 引用对应于C++的NULL指针。
所有的Java对象都存储在堆中。当一个对象包含另一个对象变量时,它只是包含另一个堆对象的指针。
在C++中,指针十分令人头疼,因为它们很容易出错。稍不小心就会创建一个错误的指针,或者使内存管理出现问题。在Java语言中,这些问题都不复存在。如果使用一个没有初始化的指针,那么运行时系统将会产生一个运行时错误,而不是生成随机的结果。另外,你不必担心内存管理问题,垃圾回收期会处理相关的事宜。
C++确实做了很大的努力,它通过支持复制构造器和赋值运算符来实现对象的自动复制。例如,一个链表(linked list)的副本是一个新链表,其内容与原始链表相同,但是有一组独立的链接。这样一来就可以适当地设计类,使它们与内置类型有相同的复制行为。在Java中,必须使用clone 方法获得一个对象的完整副本。

思考问题:
Date now = new Date();
如何通过 now 获取今天的最早的时刻(0点0份0秒),以及今天的最后
如何获取明天,下月1号,以及今年的年初和年尾