- 浏览: 332272 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
xuanyuanxiaoxue:
...
Android - LayoutInflater -
柴兴博:
不错 多谢
Android 悬浮Activity并可拖动(访悬浮歌词) -
di1984HIT:
写的很好,我收藏一下。
java之动态代理模式(JDK和cglib) -
chinacssnj:
待测试,明天测,测试的结果发给大家
网络开发上传文件到服务器 -
fx_199182:
...
Android之MediaPlayer
程序员都了解初始化的重要性,但常常会忘记同样重要的清除工作。毕竟,谁需要清除一个int 呢?但在使用程序库时,把一个对象用完后就“弃之不顾”的做法并非总是安全的。当然,Java有垃圾回收器来回收无用对象占据的内存资源。但也有特殊情 况:假定你的对象(并非使用 new)获得了一块“特殊”的内存区域,由于垃圾回收器只知道释放那些经由 new分配的内存,所以它不知道该如何释放该对象的这块 “特殊”内存。为了应对这种情况,Java允许你在类中定义一个名为finalize( )的方法。它的工作原理“应该”是这样的:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其 finalize( )方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。所以要是你打算用 finalize( ),就能在“垃圾回收时刻”做一些重要的清除工作。
这里有一个潜在的编程陷阱,因为有些程序员(特别是 C++程序员)刚开始可能会误把finalize( )当作C++中的“析构函数”(C++中销毁对象必须用到这个函数)。所以有必要明确区分一下:在 C++中,对象一定会被“销毁”(如果程序中没有错误的话);而 Java 里的对象却并非总是被“垃圾回收”的。或者换句话说:
1. 对象可能不被回收。
2. 垃圾回收并不等于“析构”。
牢记这些,你就能远离困扰。这意味着在你不再需要某个对象之前,如果必须执行某些动作,那么你得自己去做。Java并未提供“析构函数”或相似 的概念,要做类似的清除工作,你必须自己动手创建一个执行清除工作的普通方法。例如,假设某个对象在创建过程中,会将自己绘制到屏幕上。要是你不明确地从 屏幕上将其擦除,它可能永远得不到清除。如果在
finalize( )里加入某种擦除功能,当“垃圾回收”发生时(不能保证一定会发生),finalize( )得到了调用,图像就会被擦除。要是“垃圾回收”没有发生,图像就会一直保留下来。
也许你会发现,只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。如果程序执行结束,并且垃圾回收器一直都没有释放你创 建的任何对象的存储空间,则随着程序的退出,那些资源会全部交还给操作系统。这个策略是恰当的,因为垃圾回收本身也有开销,要是不使用它,那就不用支付这 部分开销了。
finalize( )用途何在?
此时,你已经明白了不该将finalize( )作为通用的清除方法。那么,finalize( )的真正用途是什么呢?
这引出了要记住的第三点:
3.垃圾回收只与内存有关。
也就是说,垃圾回收器存在的唯一原因是为了回收程序不再使用的内存。所以对于与垃圾回收有关的任何行为来说(尤其是finalize( )方法),它们也必须同内存及其回收有关。
但这是否意味着要是对象中含有其他对象,finalize( )就应该明确释放那些对象呢?不——无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。这就将对 finalize( )的需求限制到特殊情况之下:你通过某种非“创建对象”的方式为对象分配了存储空间。不过,你也看到了,Java中一切皆为对象,那这种特殊情况是怎么回 事呢?
看来之所以要有finalize( ),是由于你可能在分配内存时,采用了类似C语言中的做法而非Java中的通常做法。这种情况主要发生在使用“本地方法”的情况下,它是在Java中调用 非Java代码的一种方式。本地方法目前只支持C和C++。但它们可以调用其它语言写的代码,所以你实际上可以调用任何代码。在非Java代码中,也许会 调用类似C的malloc( )函数,用它分配存储空间,而且除非调用了free( )函数,否则存储空间将不会得到释放,从而造成内存泄露。当然,free( )是C和C++中的函数,所以你需要在finalize( )中用本地方法调用它。
至此,你或许已经明白了不要过多地使用finalize( )的道理了。对,它确实不是进行普通的清除工作的合适场所。那么,普通的清除工作应该在哪执行呢?
你必须执行清除
为清除一个对象,用户必须在进行清除的时刻调用执行清除动作的方法。听起来似乎很简单,但却与C++中的“析构函数”的概念稍有抵触。在C++ 中,所有对象都会被销毁,或者说, “应该”被销毁。如果在C++中创建了一个局部对象(就是在堆栈上创建,Java中可不行),此时的销毁动作发生在以“右花括号”为边界的、此对象作用域 的末尾处进行。如果对象是
用new创建的(类似于Java),那么当程序员调用C++的delete( )时(Java没有这个命令),就会调用相应的析构函数。如果程序员忘了,那么永远不会调用析构函数,就会出现内存泄露,对象的其他部分也不会得到清除。 这种错误很难跟踪,这也是让 C++程序员转向 Java的一个主要因素。
相反,Java不允许创建局部对象,你必须使用new。在Java中,也没有“delete”来释放对象,因为垃圾回收器会帮助你释放存储空 间。甚至可以肤浅地认为,正是由于垃圾收集机制的存在,使得 Java 没有析构函数。然而,随着学习的深入,你就会明白垃圾回收器的存在并不能完全代替析构函数。(而且你绝对不能直接调用finalize( ),所以这也不是一个恰当的
途径。)如果你希望进行除释放存储空间之外的清除工作,你还是得明确调用某个恰当的Java方法。这就等同于使用析构函数了,而且没有它方便。
记住,无论是“垃圾回收”还是“终结”,都不保证一定会发生。如果Java虚拟机(JVM)并未面临内存耗尽的情形,它是不会浪费时间在回收垃圾以恢复内存上的。
终结条件
通常,你不能指望finalize( ),你必须创建其它的“清除”方法,并且明确地调用它们。看来,finalize( )只能存在于程序员很难用到的一些晦涩用法里了。不过,finalize( )还有一个有趣的用法,它并不依赖于每次都要对finalize( )进行调用,这就是对象“终结条件”的验证。
当你对某个对象不再感兴趣,也就是它可以被清除时,这个对象应该处于某种状态,使它占用的内存可以被安全地释放。例如,要是对象代表了一个打开 的文件,在对象被回收前程序员应该关闭这个文件。只要对象中存在没有被适当清除的部分,你的程序就存在很隐晦的错误。finalize( )的价值在于可以用来最终发现这种情况,尽管它并不总是会被调用。如果某次
finalize( )的动作使得bug被发现,那你就可据此找出问题所在——这才是你真正关心的。
以下是个简单的例子,示范了可能的使用方式:
class Book { boolean checkedOut = false; Book(boolean checkOut) { checkedOut = checkOut; } void checkIn() { checkedOut = false; } public void finalize() { if(checkedOut) System.out.println("Error: checked out"); // Normally, you'll also do this: // super.finalized(); } } 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(); } }
本例的终结条件是:所有的Book对象在被当作垃圾回收前都应该被签入(check in)。但在main( )方法中,由于程序员的错误,有一本书未被签入。要是没有 finalize( )来验证终结条件,将很难发现这种错误。
注意,System.gc( )用于强制终结动作的进行。即使不这么做的话,通过重复的执行程序(假设程序将分配大量的存储空间而导致垃圾回收动作的执行),最终也能找出错误的Book对象。
发表评论
-
java clone技术 浅谈
2011-10-23 14:58 9221.java里的clone分为: A:浅复制(浅克隆): ... -
java synchronized详解
2011-10-23 10:31 754记下来,很重要。 Java语言的关键字,当它用来修饰一 ... -
Java 多线程同步 锁机制与synchronized
2011-10-21 17:25 1394打个比方:一个object就像一个大房子,大门永远打开。房子里 ... -
Java多线程编程总结(转载)
2011-10-21 16:54 756http://www.blogjava.net/cmzy/ar ... -
java内部类的总结
2011-10-15 14:42 709从Java1.1开始引入 ... -
java中的io系统详解
2011-10-10 11:26 739参考:http://expert.iteye.com/blog ... -
Java代码编写的30条建议
2011-10-10 10:22 764(1) 类名首字母应该大写 ... -
Java中局部内部类可以访问它所在方法中定义的final修饰的局部变量的合理解释
2011-09-20 11:21 1323标题有点长,可能有点 ... -
六种异常处理的陋习
2011-09-19 14:42 746你觉得自己是一个Java专 ... -
Java中常见的异常
2011-09-19 14:05 964Java 中异常的分类 所有异常,都继承自 ... -
Java异常的分类 .
2011-09-18 21:52 7921. 异常机制 异 ... -
java数组反射
2011-09-13 17:35 2085数组反射 如果因为某种原因,您并不确定参数或对象是不是数组, ... -
Java中反射机制详解
2011-09-13 14:53 1281问题: 在运行时,对一个JAVA类,能否知道属性和方 ... -
java枚举之EnumSet and EnumMap
2011-09-12 20:17 2640一:EnumSet import java.util.*; ... -
java中获取日期函数应用
2011-09-10 17:11 852(1)String类型转换成日期(Date类型) Sim ... -
java 时间格式化问题
2011-09-10 17:05 1000java 时间格式化问题 java.util.*; ... -
Java深度历险之Java泛型
2011-09-10 16:46 727Java泛型(generics)是JDK ... -
Java 集合篇
2011-09-07 18:51 7821. Java集合类库中最重要的两个接口Collec ... -
Comparable和Comparator接口
2011-09-06 13:13 769当需要排序的集合或数组不是单纯的数字型时,通常可以使用C ... -
Java对象初始化顺序
2011-09-06 10:56 1291前几天与fwb同学说起java笔试题,想起这个东西经常被考,重 ...
相关推荐
Java中finalize()详解及用法 在Java中,finalize()方法是一个重要的概念,它与final关键字息息相关。下面我们将深入探讨finalize()方法的用法和应用场景。 一、final关键字 final是Java的关键字,它所表示的是...
当一个对象被垃圾回收器标记为即将回收时,Java会尝试调用该对象的`finalize`方法,提供一个机会进行必要的清理操作。然而,这个方法并不保证一定会被执行,因此不应该依赖它来清理资源。在实际编程中,`finalize`的...
Java中的`finalize`方法是Object类的一个特殊方法,它的主要作用是在对象被垃圾收集器回收前执行清理工作。本文将详细解析`finalize`方法的实现和执行过程。 首先,了解`finalize`方法的用途:当一个对象不再被任何...
Java中的`Object`类是所有类的根,这意味着无论你定义的任何自定义类,如果没有显式地声明继承自其他类,那么它们都会隐式地继承`Object`类。`Object`类提供了基本的方法,这些方法是所有Java对象共有的。下面我们将...
总的来说,Java的`finalize()`方法提供了一种在对象被垃圾收集器回收前进行额外操作的机会,但这应该谨慎使用,因为它的执行时间和效果都是不确定的。在设计程序时,优先考虑使用Java提供的自动资源管理机制,如`try...
在Java中,`System.gc()`方法只是建议JVM进行垃圾回收,但是否实际执行取决于JVM的决定。此外,需要注意的是,对象的`finalize`方法的执行顺序是不确定的。尽管某些文档可能指出对象的`finalize`方法会按照特定的...
Java编程语言虽然以其稳定性和强大的功能受到广大开发者喜爱,但正如...阅读"Java.Bug模式详解.pdf"这份资料,将有助于深入理解这些模式,并学习如何避免它们。持续学习和实践,是成为一名优秀的Java开发者的必经之路。
Java中的finalize()方法覆盖实例代码详解 finalize()方法是Java中的一个特殊方法,它可以在对象被垃圾回收器回收之前执行一次。这个方法可以用来释放对象持有的资源,但是它的使用需要非常小心,因为它带有很多不...
当系统将要发生内存溢出异常前,将会把这些对象列进回收范围之中进行第二次回收。 - **弱引用(Weak Reference)**:仅当GC进行时,无论系统内存是否充足,都会回收弱引用的对象。 - **虚引用(Phantom Reference)*...
2. **Finalizable**:当GC发现一个对象不再可达(即没有其他对象引用它),这个对象会被放入一个名为Finalizer队列(F Queue)中,准备进行`finalize()`方法的执行。这是对象生命周期中的一个过渡阶段。 3. **...
19. **Java无goto**:Java语言中没有goto关键字,鼓励使用结构化编程。 20. **length()方法**:数组有`length`属性而非`length()`方法,String有`length()`方法返回字符串长度。 21. **Overload与Override**:...
- `finalize`:是一个特殊的方法,当垃圾收集器准备回收一个对象时,会先调用该对象的finalize()方法,供对象进行必要的清理工作。但这并不保证一定会执行,且不推荐用于资源清理,因为执行时机不确定。 2. **匿名...
在Java面试中,了解final、finally、finalize的区别是非常重要的。final是一个修饰符(关键字),如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。将变量或方法声明为final,可以保证...
Java程序员面试时,面试官通常会...以上问题涵盖了Java的基础语法、集合框架、异常处理、多线程、内存管理等多个核心知识点,是面试中常见的考察点。理解并熟练掌握这些内容,对于成为一名合格的Java程序员至关重要。
- C#中的析构函数用`~`符号标记,但其功能与Java中的`finalize`方法不同。 - 两种语言都支持接口和抽象类的概念,但具体实现有差别。 - 泛型在Java中使用`<T>`语法,在C#中则更灵活,支持类型参数约束等特性。 7...
在Java中,`finalize()`方法是一种特殊的机制,用于对象被销毁前执行清理工作。不过,这个方法的使用并不推荐,主要有以下原因: - **不可预测性**:对象是否会被调用`finalize()`方法以及何时调用都是不确定的。 - ...
本文将对 Java 面试题进行详解,涵盖 final、finally、finalize、Anonymous Inner Class、Static Nested Class、Inner Class、& 和&&、HashMap 和 Hashtable、Collection 和 Collections 等知识点。 一...
Java 终止函数详解 Java 终止函数是 Java 语言中的一种机制,用于在对象不再被需要时清除任务。它与 Java 结构函数相反,后者创建和初始化了一个 Java 类实例。Java 终止函数可以被用来清除任务,例如释放文件描述...
为了在激烈的求职竞争中脱颖而出,Java程序员必须对基础知识有深入的理解,并能够应对各种面试中的问题。本资源集合了Java面试中常见的问题,涵盖了从基础概念到高级特性的广泛话题。 首先,我们来看“JAVA面试题...