Java面试中经常会遇到一个问题:final、finally、finalize的区别?
今天我只谈大家回答的最不准确也误解最深的一个 —— finalize。谈finalize() 方法之前需要先了解一下Java垃圾回收机制。
Java有垃圾回收期负责回收无用对象占据的内存资源。但也有特殊情况:假定你的对象(并非使用new)获得了一块“特殊”的内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以它不知道该如何释放该对象的这块“特殊”内存。【gc只负责jvm内部分配的资源,所以如果通过jni获取了系统资源,肯定无法自动回收. 】, 为了应对这种情况,java允许在类中定义一个名为finalize()的方法。它的工作原理“假定”是这样的:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize() 方法,并且在下一次垃圾回收动作发生时,才真正回收对象占用的内存。
这里有一个编程陷阱:基于上述对finalize的理解,很容易把finalize和C++中的析构函数对应起来。其实他们两个很不一样,在C++中,对象一定会被销毁;而java里的对象却并非总是被垃圾回收器回收。也许你会发现,只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。(因为垃圾回收本身也有开销,要是不使用它就不用支付这部分开销了)
finalize()的真正用途:
之所以要有finalize(),是由于在分配本地内存时可能采用了类似C语言中的做法,而非Java中的通常做法。这种情况主要发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。本地方法目前只支持C和C++,但它们可以调用其他语言写的代码,所以实际上可以调用任何代码。在非Java代码中,也许会调用C的malloc()函数系列来分配存储空间,而且除非调用了free()函数,否则存储空间将得不到释放,从而造成内存泄露。当然,free()是C和C++中的函数,所以要在finalize()中用本地方法调用它。
至此,或许明白了finalize的确实不是进行普通的清理工作,对于开头提到的面试问题,如果可以根据自己对本文描述内容的理解予以回答,也已足够。
相关推荐
finalize() 方法的调用机制是:在垃圾回收器准备回收对象时,首先调用 finalize() 方法,然后在下一次垃圾回收过程中,真正回收对象的内存。finalize() 方法可以在以下三种情况下被调用:1. 所有对象被 Garbage ...
垃圾收集器会在下一次垃圾收集周期中调用这些对象的`finalize()`方法,然后才真正回收内存。 需要注意的是,过度依赖`finalize()`方法可能会导致性能问题,因为它增加了垃圾收集的复杂性。此外,`finalize()`方法的...
C#中的Destructor只是定义Finalize方法的捷径,而不是真正的析构函数。 错误10:没有正确地理解.NET Framework的可管理环境 C#程序员需要理解.NET Framework的可管理环境,以便正确地使用C#语言和.NET Framework。...
7. **finalize()方法**:在对象被垃圾回收前,Java会尝试调用`finalize()`方法,提供一个机会清理资源。但这不应依赖于`finalize()`进行关键资源的释放,因为它不保证会被执行。 8. **访问对象的数据和方法**:通过...
建议避免过度依赖`finalize()`,而是使用try-finally结构或使用Java 7及更高版本的try-with-resources语句来确保资源的正确释放。 2、`System.gc()`和`Runtime.getRuntime().gc()`: 这两个方法是向JVM发出垃圾回收...
Finalizer线程会尝试执行这些对象的finalize()方法,如果对象在这期间建立了新的引用关系,就会避免被回收。否则,第二次标记后,对象将被真正回收。需要注意的是,finalize()方法只会被调用一次。 在JDK 1.2之后,...
- 使用方法同步而非代码块同步,以减少锁的粒度。 #### 八、使用StringBuilder和StringBuffer进行字符串连接 字符串连接操作在Java中非常常见,但如果没有适当的选择工具,则可能会影响性能。StringBuilder和...
7. **谨慎使用synchronized**:同步可能导致性能下降和死锁,只在真正需要的地方使用,并尽量缩小同步范围,使用方法级别同步代替代码块同步。 8. **StringBuilder与StringBuffer**:字符串拼接应使用StringBuilder...
`finalize()`是`Object`类的一个方法,所有Java类都继承自`Object`,因此默认具有这个方法。 1. `finalize()`的工作原理:当垃圾收集器准备回收对象的内存时,会首先调用`finalize()`方法。然后在下一次垃圾收集时...
因此,在设计应用时应尽量避免频繁的资源创建与销毁,并合理使用析构函数或IDisposable接口的Dispose方法。 通过以上的知识点,可以全面了解C#中析构函数的概念、特性以及在内存管理和资源清理中的作用。在实际编程...
15. **避免使用 finalize() 方法进行资源清理**: finalize()方法的执行时间不确定,且可能导致性能问题。应该使用try-with-resources或其他显式关闭资源的方式。 这些仅是《Effective Java》中众多知识点的冰山一角...
- **运行 finalize 方法**:对于被标记为垃圾的对象,如果该对象定义了 `finalize()` 方法,那么在真正回收之前,JVM 会尝试执行这个方法。这是对象清理资源的最后机会,例如关闭文件句柄等。然而,在现代 Java 版本...
对于`Base`类来说,它的VTable包含所有虚方法的指针,包括继承自`System.Object`的四个虚方法(`ToString`、`Equals`、`GetHashCode`、`Finalize`)和自己声明的虚方法。 - **子类方法表的变化**:对于`Derived`类,...
当对象即将被垃圾回收时,如果对象实现了`finalize()`方法,JVM会在回收之前调用该方法。需要注意的是,`finalize()`方法的调用是不确定的,并且可能只被调用一次。 #### 析构函数(finalization)的目的是什么 析构...
6. **析构函数**:虽然在Java中没有真正的析构函数,但我们可以使用 finalize() 方法进行资源清理。不过,不推荐依赖 finalize() 进行资源管理,因为其调用时机不可靠。 7. **接口**:接口在Java中是一种完全抽象的...
- abstract不能与static或final一起使用,因为它们的生命周期和作用范围不同。 - abstract不能与native一起使用,因为抽象方法没有具体实现。 - abstract不能与synchronized一起使用,因为抽象方法没有定义具体...
2. finalize()方法:当垃圾回收器准备回收一个对象时,可能会调用它的finalize()方法。然而,这不是一定的,因为垃圾回收的时机由JVM决定,程序员无法直接控制。此外,System.gc()虽然可以请求执行垃圾回收,但是否...
- **实践建议:** 尽量减少变量的作用域,只在真正需要的地方声明和使用变量。 #### 21. 常量与枚举 - **要点:** 对于固定不变的值,考虑使用常量或枚举类型。 - **实践建议:** 使用`enum`来定义有限的一组值,...