《Java编程思维》学习笔记之初始化与清理
初始化
1、区分重载的方法
要是几个方法有相同的名字,Java如何才能知道你指的是哪一个呢?其实规则很简单:每个重载的方法都必须有一个独一无二的参数类型列表。
有些人可能会想:“在区分重载方法的时候,为什么只能以类名和方法的形参列表作为标准呢?能否考虑用方法的返回值来区分呢?”比如下面两个方法,虽然它们有同样的名字和形式参数,但却很容易区分它们:
void f(){} int f(){return 1;}
只要编译器可以根据语境明确判断出语义中,比如在int x=f()中,那么的确可以据此区分重载方法。不过,有时你并不关心方法的返回值,你想要的是方法调用的其他效果,这时你可能会调用方法而忽略其返回值。所以如果像下面这样调用方法:
f();
此时Java如何才能判断该调用哪一个f()呢?
因此,根据方法的返回值来区分重载方法是行不能的。
2、默认构造器
如果某个类已经定义了一个构造器(无论是否有参数),编译器都不会帮你自动创建默认构造器:
class Bird2{ Bird2(int i){} } public class NoSynthesis{ public static void main(String[] args){ //! Bird2 b = new Bird2(); //没有默认的,此处调用会出错 Bird2 b2 = new Bird2(1); } }
3、this关键字
如果有同一个类型的两个对象,分别是a和b。
class Banana{ void peel(int i){ /*........*/ } } public class BananaPeel{ public static void main(String[] args){ Banana a = new Banana(), b = new Banana(); a.peel(1); b.peel(2); } }
如果只有一个peel()方法,它如何知道是被a还是被b所调用的呢?
为了能用简便、面向对象的语法来编写代码----即“发送消息给对象”,编译器做了一些幕后工作。它暗自把“所操作对象的引用”作为第一个参数传递给peel()方法。所以上述两个方法的调用 就变成了这样:
Banana.peel(a,1); Banana.peel(b,1);
这是内部的表示形式。我们并不能这样书写代码,并试图通过编译。
this关键字只能在方法内部使用,表示对“调用方法的那个对象”的引用。this的用法与其他对象引用并无不同。但要注意,如果在方法内部调用同一个类的另一个方法,就不必使用this,直接调用即可。
可能为一个类写了多个构造器,有时可能想在一个构造器中调用另一个构造器,以避免重复代码。可用this关键字做到这一点。在构造器中,如果为this添加了参数列表,那么就有了不同的含义。这将产生对符合此参数列表的某个构造器的明确引用。
public class Flower{ String s = "abc"; Flower(int petals){ /*...*/ } Flower(String ss){ /*...*/ s = ss; } Flower(String s,int petals){ this(petals); //this(s);//类似的调用不能调用两次 this.s = s; /*...*/ } }
清理:终结处理和垃圾回收
程序员都了解初始化的重要性,但常常会忘记同样也重要的清理工作。毕竟,谁需要清理一个int呢?但在使用程序库时,把一个对象用完后就“弃之不顾”的做法并非总是安全的。当然,Java有垃圾回收器负责回收无用对象占据的内存资源。但也有特殊情况:假定你的对象(并非使用new)获得了一块“特殊”的内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以它不知道该如何释放该对象的这块“特殊”内存。为了应对这种情况,Java允许在类中定义一个名为finalize()的方法。它的工作原理“假定”是这样的:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并有在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。所以要是你打算用finalize(),就能在垃圾回收时刻做一些重要的清理工作。
这里有一个潜在的编程陷阱,因为有些程序员(特别是c++程序员)刚开始可能会误把finalize()当作c++中的析构函数(c++中销毁对象必须用到这个函数)。所以有必要明确区分一下:在c++中,对象一定会被销毁(如果程序中没有bug的话);而Java里的对象并非总是被垃圾回收。或者换句话说 :
1.对象可能不被垃圾回收。
2.垃圾回收并不等于“析构”。
Java并未提供“析构函数”或相似的概念,要做类似的清理工作,必须自己动手创建一个执行清理工作的普通方法。例如,假设某个对象在创建过程中会将自己绘制到屏幕上,如果不是明确地从屏幕上将其擦除,它可能永远得不到清理。如果在finalize()里加入某种擦除功能,当“垃圾回收”发生时(不能保证一定会发生),finalize()得到调用,图像就会被擦除。要是“垃圾回收”没有发生,图像就会一直保留下来。
1、finalize()的用途何在?
3.垃圾回收只与内存有关。
也就是说,使用垃圾回收器的唯一原因是为了回收程序不再使用的内存。所以对于与垃圾回收有关的任何行为来说(尤其是finalize()方法),它们也必须同内存及其回收有关。
但这是否意味着要是对象中含有其他对象,finalize()就应该明确释放那些对象呢?不,无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。这将finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。
finalize()还有一个有趣的用法,它并不依赖于每次都要对finalize()进行调用,这就是对对象终结条件的验证。当对某个对象不再感兴趣----也就是它可以被清理了,这个对象应该处于某种状态,使它占用的内存可以被安全释放。例如,要是对象代表了一个打开的文件,在对象被回收前程序员应该关闭这个文件。只要对象中存在没有被适当清理的部分,程序就存在很隐晦的缺陷。finalize()方法可以用来最终发现这种情况----尽管它并不总是会被调用。
//Using finalize() to detect an object that hasn't been properly cleaned up class Book{ boolean checkedOut = false; Book(boolean checkOut){ checkedOut = checkOut; } void checkIn(){ checkedOut = false; } protected void finalize(){ if(checkedOut){ System.out.println("Error:checked out!"); //Normally,you'll also do this //super.finalize(); } } } public class TerminationCondition{ public static void main(String[] args){ Book novel = new Book(true); //Proper cleanup novel.checkIn(); //Drop the reference,forget to clean up new Book(true); //force garbage collection & finalization System.gc(); } }
未完,待续。。。。