5.2 方法重载
Java的方法重载与C++一样,不能以返回值作为两个函数重载的区别。
另外,后面的章节中会有介绍,Java存在一个叫做协变返回类型的:子类中的一个覆盖方法可以返回基类被覆盖方法返回值的子类。
5.4 this关键字
Java中this关键字同样代表正在调用方法的对象本身,是编译器为每个非static方法传递的第一个参数(隐藏传递,程序员感觉不到,与Java,C++这种隐藏传递相对的是,Python要求明确方法的第一个参数为self,也就是对象自己的引用。)
Java中的this有一个更重要的用途,在构造函数里调用重载的其他构造函数。C++中,一个构造函数不可以调用另外一个构造函数,因为在C++中构造函数有着初始化vtable的作用,重复构造vtable是不允许的。
5.5 清理:终结处理和垃圾回收
关于finalize()方法有关的要牢记的三点:
- 对象可能不被垃圾回收
- 垃圾回收并不等于析构
- 垃圾回收只与内存有关
关于第三点有必要引用书上的原话:“也就是说,使用垃圾回收器的唯一原因是为了回收程序不再使用的内存。所以对于与垃圾回收有关的任何行为来说(尤其是finalize()方法),它们也必须同内存及其回收有关。但这是否意味着要是对象中含有其他对象,finalize()就应该明确释放那些对象呢?不,无论对象是如何创建的,垃圾回收器都会负责释放对象占据的内存。这就将finalize()的需求限制到一种特殊情况,即通过某种创建对象以外的方式为对象分配了存储空间。”-- 本地方法分配的内存需要在finalize()中释放,比如对象的某个域由C的malloc来分配内存,这时候需要在finalize()中调用相应的free方法类释放内存。
5.5.3 终结条件
作为finalize()方法的一种使用技巧,通过GC动作检查你的程序是否正确,比如书中的这个列子,所有的Book对象在程序结束的时候(或者说对象不再使用的时候)都应该是回到图书馆的。
import static java.lang.System.out; class Book { boolean checkedOut = false; Book(boolean checkOut) { checkedOut = checkOut; } void checkIn() { checkedOut = false; } protected void finalize() { if(checkedOut) out.println("Error: checked out"); // Normally, you'll also do this // super.finalize(); // Call the base class version } } public class TerminationCondition { public static void main(String args[]){ Book novel = new Book(true); // Proper cleanup: novel.checkIn(); // Drop the reference. forgot to cleanup new Book(true); // Force garbage collection & finalization System.gc(); } } /*Output: Error: checked out */
5.6 成员初始化
类的每一个Primitive数据成员都会获得一个初始值(0,NULL or False)。
指定初始化,也可以用函数,但这个函数如果有参数的话,那参数必须同样被初始化。
5.7 构造器初始化
import static java.lang.System.out; class Dog { public Dog(String name) { out.println(name + " constructor"); } } public class HelloWorld{ private static Dog Dog1 = new Dog("Dog1"); private Dog dog2 = new Dog("Dog2"); private Dog dog3; private Dog dog4 = new Dog("Dog4"); private static Dog dog5; private Dog dog6 = new Dog("Dog6"); public static void main(String []args){ new HelloWorld(); out.println("----"); new HelloWorld(); } { dog3 = new Dog("Dog3"); } static { dog5 = new Dog("Dog5"); } public HelloWorld(){ dog6 = new Dog("Dog6"); } }
总结一下对象的创建过程:
- 及时没有显示地使用static关键字,构造器实际上也是静态方法。因此当首次创建类型为Dog的对象时,或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
- 然后加载Dog.class(后面会学到,这将创建一个Class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
- 当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
- 这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值(0,False&Null)。
- 执行所有出现于字段定义出的初始化动作。
- 执行构造器。
5.8 数组的初始化
基本数据类型的数组是一组包含了基本类型数据的数组,自动被初始化为"空";对象的数组是一组包含了引用的数组,每个元素都是一个空引用,如果没有赋值。
1 import static java.lang.System.out; 2 public class HelloWorld{ 3 public static void main(String []args){ 4 int arr1[] = new int[2]; 5 for(int item : arr1) 6 out.println(item); 7 out.println("----"); 8 Integer arr2[] = new Integer[2]; 9 for(Integer item : arr2) 10 out.println(item); 11 out.println("----"); 12 arr2[0] = new Integer(0); 13 arr2[1] = new Integer(1); 14 for(Integer item : arr2) 15 out.println(item); 16 } 17 }/*Output 18 0 19 0 20 ---- 21 null 22 null 23 ---- 24 0 25 1 26 */ 27