×

消息

EU e-Privacy Directive

This website uses cookies to manage authentication, navigation, and other functions. By using our website, you agree that we can place these types of cookies on your device.

View e-Privacy Directive Documents

You have declined cookies. This decision can be reversed.

避免使用finalizer

Java语言规范里没有要求finalizer何时被执行,甚至没要求它一定要被执行。各种不同的jvm实现完全可能以它们自己的方式来处理finalizer,所以finalizer里的代码执行没有任何保障,从这点上来说,很多c++程序员把finalizer作为c++析构函数在Java中的对应功能是完全错误的。如果错误地依赖finalizer来释放被占用的资源或者执行某些时序任务,很可能会造成不可预料的错误行为。

Java面试里面一个烂大街的问题就是System.gc()方法有什么作用,其实还有一个类似的方法System.runFinalization(),两者没太大区别,都是向jvm提出gc请求,但根本无法保证jvm会及时作出响应。当然,这两个方法还是提高了finalizer被执行的可能性。

finalizer的另一个问题是异常处理。当其中的代码抛出异常时,如果没有显式定义catch处理,这些异常将被完全忽略,所在线程会瞬间终止,连stack trace都不会打印。

移除过期的对象引用

这节讲的是关于内存泄露的问题。Java有三大主要的内存泄露来源:

1.开发者自己维护的内存

2.缓存

3.listener和callback

第一类:开发者自己维护的内存。这类问题通常是开发者从其它编程语言(例如c++)带来的坏习惯导致,比如下面这段代码:

避免创建不必要的对象

最常见的例子是String,一个小小的String对象看起来不起眼,但在复杂的大型系统中,如果不恰当创建,可能会带来极大的性能开销,比如:

String s = new String("stringette"); // DON'T DO THIS!

这行代码的问题是,作为参数的"stringette"本身已经是所需要的String对象了,菜鸟程序员却调用一个String类的构造函数来再次构造它。这行代码每执行一次,就会在栈里面建立一个一模一样的"stringette"对象。在高频执行的环境下,内存开销会非常大,甚至引起stack overflow。正确的做法是:

又是简单而常用的东西

通过私有构造函数来禁止类被对象化

主要用于各种helper或者factory类,这些类只包含一些工具性的方法,通过静态调用提供服务,完全没必要被对象化。但如果不做特殊处理,编译器会为这些类提供一个默认的无参数构造函数,所以仍然会偶尔被粗心的用户对象化。需要注意的是,把它们定义为抽象类(abstract)并不管用,因为只要定义一个子类,对象化仍然可以完成,而且抽象关键字很容易引起误导,让人觉得这些类就是用来继承的,这就与我们的目的背道而驰了。

正确的方法是定义一个私有的无参数构造函数:

这一节非常简单

用枚举类型来定义Singleton

当然枚举类型从Java5才被引入,版本太旧就不能玩了。

传统的Singleton有两种创建方法,一是final公共对象,即把要作为Singleton的对象定义为public static final,把构造函数定义成private,就完事:

这一节看起来很简单,却还藏着不少好玩的东西。

当构造函数需要很多(4个以上)参数时,优先使用builder设计模式

先说这种情况下传统的做法,一种方法是telescoping constructor(套筒式构造函数?),就用书中的例子:

第6页 共10页