Learn Java for Android Development Second Edition 笔记(四)

续-终极祖类Object

finalize()

该方法是Java的garbage collector在检测到没有任何引用到某个对象时,清理该对象资源所会调用的。子类可以覆盖该方法来实现其他的clean up。
但是不要依赖于finalize方法,在程序退出之前,虚拟机有可能一直不会调用该方法。同时,不要依赖该方法来释放有限的系统资源如文件描述符。
finalize一般写法如下:
protected void finalize() throws Throwable
{
try
{
// Perform subclass cleanup.
}
finally
{
super.finalize();
}
}
因为以上cleanup的代码有可能抛出一个异常,如果没有try finally代码,那么super.finalize就不会执行。所以在函数声明的时候要加上throws Throwable。
如果一个异常抛出后,Java的异常处理逻辑就会执行finally里面包含的代码。
finalize方法常被用来resurrection(复活)对象,这样可以实现对象池(如果某些对象的创建非常耗资源)。在finalize函数里将this指针也就是将要被释放的对象赋值给另外一个长期存在的变量,这样就不会被释放掉。A resurrected object’s finalizer cannot be called again.

hashCode()

该函数返回代表当前对象的hash code,是一个32位整数。计算hash code的过程称作hashing。
当Override equals时,需要同时Override hashCode,实现hashCode需要遵循以下原则:
  • 在一次程序执行时,同样对象返回的值一样。但是程序这次执行和上次执行,结果可以不一样。
  • 如果两个对象equals方法返回结果一样,那么hashCode()返回结果也应该一致。
  • 如果两个对象equals方法返回结果不一样,没有要求hashCode返回的整数值要不一样,但最好不一样,这样可以提高未来存储在hash table的性能。
如果没有遵守以上要求,那么将这种类应用在基于hash的collection时,会工作不正常。
如果Override equals方法,但是没有override hashCode,那么很有可能违反以上第二条规定,会导致错误结果,如以下示例:
java.util.Map<Point, String> map = new java.util.HashMap<Point, String>();
map.put(p1, "first point");
System.out.println(map.get(p1)); // Output: first point
System.out.println(map.get(new Point(10, 20))); // Output: null
以上代码里,p1事先初始化好了和Point1(10,20)逻辑上值一致,但是最后一行里却取不到p1的值出来,就是因为Point类没有Override hashCode方法。

toString()

该函数返回一个字符串,表示当前对象的名字。缺省情况下是类名+@+16进制表示的hashcode值,子类可以覆盖该方法,用更有意义的字符串表示。

Composition(组合)

继承和组合,是实现代码复用的两种不同方法。继承是基于子类与父类是“is-a”的关系,组合是基于一个类包含另一个类,是“has-a”的关系。Java里实现组合的一种方式是将一个对象做为另一个对象的成员变量来实现。

实现继承时的一个麻烦

当一个父类设计的可扩展性不够好或者开发者对父类没有完全控制时,实现继承可能会破坏封装。当子类依赖于父类的实现细节,而父类的新版本发生改变,子类有可能崩溃。
例如,子类调用父类的一个函数,父类的该函数里面有可能会调用子类覆盖的一个子函数。当父类新增一个函数,子类没有对应的覆盖函数。
通过组合的方式有时候可以解决继承的麻烦,新建一个类包含需要wrapper的成员类,实现与成员类相同的方法名字。如以下例子:
public class LoggingApptCalendar
{
private ApptCalendar apptCal;
public LoggingApptCalendar(ApptCalendar apptCal)
{
this.apptCal = apptCal;
}
public void addAppt(Appt appt)
{
Logger.log(appt.toString());
apptCal.addAppt(appt);
}
public void addAppts(Appt[] appts)
{
for (int i = 0; i < appts.length; i++)
Logger.log(appts[i].toString());
apptCal.addAppts(appts);
}
}
通过以上方法,wrapper的类就不会破坏“父类”的封装。
当子类和父类有“is-a”的关系,且父类完全控制,设计文档完好,那么就使用继承。否则,使用wrapper class。
design and document for class extension:Design意味着提供了protected方法并且确保构造函数和clone方法绝不会调用可被覆盖的函数。Document意味着清楚知道覆盖函数的影响。
Wrapper类不能用于callback的框架中,因为被包装的对象函数里面不知道包装对象的this指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值