Think in java第四章 初始化和清除(Initialization&CleanUp)
作者的blog:http://www.matrix.org.cn/blog/cleverpig
主要章节内容:
4.1 构建器
4.2 方法过载
4.3 收尾和垃圾收集
4.4 成员初始化
关键词:Constructor,finalize(),初始化顺序
重点整理:
1.构造函数
要点:
构
建器(Constructor)属于一种较特殊的方法类型,因为它没有返回值.这与void返回值存在着明显的区别。对于void返回值,尽管方法本身不
会自动返回什么,但仍然可以让它返回另一些东西。构建器则不同,它不仅什么也不会自动返回,而且根本不能有任何选择.若创建一个没有构件器的类,则编译器
会自动创建一个默认构件器.
2.finalize()和gc()
(1)问题:finalize()函数是干嘛的?Java不是有Garbage Collection(以下简称gc)来负责回收内存吗?
回答:
gc
只能清除在堆上分配的内存(纯java语言的所有对象都在堆上使用new分配内存),而不能清除栈上分配的内存(当使用JNI技术时,可能会在栈上分配内
存,例如java调用c程序,而该c程序使用malloc分配内存时).因此,如果某些对象被分配了栈上的内存区域,那gc就管不着了,对这样的对象进行
内存回收就要靠finalize().
举个例子来说,当java
调用非java方法时(这种方法可能是c或是c++的),在非java代码内部也许调用了c的malloc()函数来分配内存,而且除非调用那个了
free()
否则不会释放内存(因为free()是c的函数),这个时候要进行释放内存的工作,gc是不起作用的,因而需要在finalize()内部的一个固有方法
调用它(free()).
finalize的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存.所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除或清扫工作.
(2)问题:finalize()在什么时候被调用?
回答:
有三种情况
1.所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候.
2.程序退出时为每个对象调用一次finalize方法。
3.显式的调用finalize方法
除此以外,正常情况下,当某个对象被系统收集为无用信息的时候,finalize()将被自动调用,但是jvm不保证finalize()一定被调用,也就是说,finalize()的调用是不确定的,这也就是为什么sun不提倡使用finalize()的原因.
3. this
要点:
this关键字只能在方法中使用,它能为调用该方法的对象提供相应的句柄,使得同一个类产生的不同对象实例在调用同一方法的时候,系统能判断出是哪一个对象在进行调用.
比如:
MyObject a=new MyObject();
MyObject b=new MyObject();
a.f();// (3)
b.f();// (4)
编译器在编译的时候,实际上是将(3),(4)句解释为
MyObject.f(a);
MyObject.f(b);
的,这样就将调用了该方法的对象的信息传到了方法中,也就是传给了this,就可以通过this表示调用该方法的对象实例.
用this的概念还可以解释为什么在静态方法中不能调用非静态方法和元素,这是因为静态方法中没有this,也就是说我们不能获得调用该方法的对象的句柄.既然找不到这个对象实例,我们又怎么能够在其中调用对象实例的方法和元素呢?
那
为什么静态方法没有this呢?用静态方法的概念可以来理解这个问题.静态方法是类方法,是所有对象实例公用的方法.它不属于某一个具体的对象实例,因此
也无法用this来体现这个实例.这和非静态方法是不一样的.打个比方,在一个局域网内的几个用户每个人都有一台客户机,但都访问一台公共的服务器.对于
每台客户机来说,它的this就是使用它的用户.而对于服务器来说,它没有this,因为它是大家公用的,不针对某一个具体的客户.
4.对象初始化
要点:
1.对象只有在创建的时候,需要使用它的时候才进行初始化,否则永远都不会初始化.
2.对象进行初始化是有一定顺序的,无论在定义的时候各个成员的摆放位置如何.首先是静态成员和对象,然后是非静态成员和对象,最后才运行构造器.
3.静态成员和对象有且只有一次初始化过程,这个过程发生在第一次创建对象或者第一次使用类的静态成员和对象的时候.
以一个名为Dog的类为例,它的对象实例初始化过程如下:
(1) 类型为Dog的一个对象首次创建时,或者Dog类的static方法/static字段首次访问时,Java解释器必须找到Dog.class(在事先设好的类路径里搜索)。
(2) 找到Dog.class后,它的所有static初始化模块都会运行。因此,static初始化仅发生一次?D?D在Class对象首次载入的时候。
(3) 创建一个new Dog()时,Dog对象的构建进程首先会在内存堆(Heap)里为一个Dog对象分配足够多的存储空间。
(4) 这种存储空间会清为零,将Dog中的所有基本类型设为它们的默认值
(5) 进行字段定义时发生的所有初始化都会执行。
(6) 执行构建器。正如第6章将要讲到的那样,这实际可能要求进行相当多的操作,特别是在涉及继承的时候
5.数组的初始化
数组包括基本数据类型数组和对象数组,其中对于对象数组的初始化,经常会出现"Exception"错误.比如下面的程序
问题代码如下:
public userInfo[] getUsersInfo() {
userInfo[] usersInfo=null;
if (users.size()!=0) {
usersInfo=new userInfo[users.size()];
for(int i=0;i< usersInfo.length;i++) {
//+-------------------出问题的地方-----------------
usersInfo[i].name=((User)(users.elementAt(i))).name;
usersInfo[i].type=((User)(users.elementAt(i))).type;
usersInfo[i].userID=((User)(users.elementAt(i))).userID;
//+-------------------出问题的地方-----------------
}
System.out.println("here");
return usersInfo;
}else {
return null;
}
}
其中userInfo的定义为
class userInfo{
userInfo(String name,int type,int userID){
this.name=name;
this.type=type;
this.userID=userID;
}
String name;
int type;
int userID;
}
运行到程序中标出的问题区域时,系统显示NullPointerException,为什么会这样呢?
这是因为,Java在定义数组的时候
usersInfo=new userInfo[users.size()];
并没有给数组元素分配内存,它只是一个句柄数组,数组中的对象还没有初始化.因此数组中的每个对象都需要new之后才可以访问.例如:
A[] a=new A[2];
for(int i=0;i<2;i++)
a[i] = new A();
这样才能a[i].someMethod()
因此上面的程序应该改为
public userInfo[] getUsersInfo() {
userInfo[] usersInfo=null;
if (users.size()!=0) {
usersInfo=new userInfo[users.size()];
for(int i=0;i< usersInfo.length;i++) {
//+-------------------修改的地方-----------------
usersInfo[i]=new userInfo(((User)(users.elementAt(i))).name,
((User)(users.elementAt(i))).type,
((User)(users.elementAt(i))).userID);
}
//+-------------------修改的地方-----------------
return usersInfo;
}else {
return null;
}
}
就没问题了
分享到:
相关推荐
对于`finalize()`方法,Java有一个特殊的 finalize 队列,当对象被标记为可回收且其`finalize()`未被执行过时,会被放入这个队列。垃圾收集器会在下一次垃圾收集周期中调用这些对象的`finalize()`方法,然后才真正...
#### 三、详解`finalize()`函数 `finalize()`方法是`Object`类中的一个受保护的方法,所有的Java类都是`Object`的子类,因此都可以访问到这个方法。尽管如此,`finalize()`方法并不是自动调用的,需要手动实现链式...
`Finalize()`方法是对象析构函数,与C++的析构函数类似,用于在对象被GC回收前执行必要的清理工作。不同于`Dispose()`,`Finalize()`是不可控的,因为GC何时运行析构函数是不确定的。这可能导致资源释放延迟,甚至在...
《JVM垃圾回收与调优详解1》 Java虚拟机(JVM)的内存管理和垃圾回收是其性能优化的关键环节。本文主要探讨JVM内存分配、对象回收的判断标准以及垃圾收集算法。 1. JVM内存分配与回收 在JVM中,内存分为新生代、...
本文将详细探讨JVM中的垃圾回收与调优,重点包括内存分配策略、对象的生命周期以及垃圾回收的判断标准。 首先,JVM内存分为新生代(Young Generation)、老年代(Tenured Generation)和持久代(Permanent ...
一旦`finalize()`执行过,对象的finalizable标志就会被清除,之后即使对象再次变得不可达,GC也不会再调用`finalize()`。 Java提供了几种不同类型的引用,如SoftReference和WeakReference,来帮助管理对象的生命...
了解和掌握GC机制与内存分配策略对于Java开发者来说至关重要,因为这有助于优化应用程序的性能和稳定性。 1. **垃圾收集器**: - **垃圾收集器**是实现GC的具体工具,不同的JVM实现可能有不同的垃圾收集器。例如,...
在可达性分析后,所有与GC Roots无连接的对象会被首次标记。如果对象没有覆盖finalize()方法或者finalize()已被调用过,那么它将被视为垃圾,准备回收。如果对象覆盖了finalize()且未被调用,对象会被放入F-Queue...
例如 `-Xms` 和 `-Xmx` 分别设置JVM初始堆大小和最大堆大小,`-XX:NewRatio` 控制新生代和老年代的比例,`-XX:SurvivorRatio` 设置Eden区与Survivor区的比例,以及`-XX:+UseConcMarkSweepGC` 或 `-XX:+UseG1GC` 来...
### Java垃圾回收详解 #### 垃圾回收基础概念 在Java编程语言中,垃圾回收(Garbage Collection, GC)是一项自动化的内存管理机制。它能够自动检测并释放那些不再被程序使用的对象所占用的内存空间,从而有效地...
Java垃圾收集器使用小诀窍详解 Java垃圾收集器是Java虚拟机(JVM)中一个非常重要的组件,它负责管理Java程序中的内存资源,防止内存泄露和溢出。垃圾收集器的使用小诀窍可以帮助开发者写出高效的Java程序,避免...
虚引用必须与引用队列一起使用,当对象被回收时,虚引用会被放入队列。 这些引用类型之间的转换可以在适当的时候发生,例如,当对象失去所有强、软、弱引用时,它们会变成虚引用,最终被垃圾收集器回收。 总之,...
- **GC的附加动作**:包括停止其他线程执行以确保一致性,运行对象的finalize方法(如果尚未执行),以及释放内存给新对象使用。 4. **GC优化策略**: - **调整新生代和老年代的比例**:通过设置`NewRatio`参数...
16. **GC与原因**:GC(Garbage Collector)是Java自动内存管理的一部分,避免程序员手动管理内存,防止内存泄漏和溢出。 17. **Strings = new String("xyz");**:创建了两个对象,一个是字符串字面量"xyz",存在于...
### JAVA中销毁一个对象的方法详解 #### 一、垃圾回收器(Garbage Collector) 垃圾回收器是Java平台中最常用的对象销毁方法之一。它能够自动管理内存,释放不再使用的对象所占用的空间,从而避免了手动管理内存所...
Java程序员面试时,面试官通常会关注候选人的基础知识掌握程度,包括语言特性和常见的数据结构与算法。以下是对部分题目及其涉及知识点的详细解释: 1. **final, finally, finalize的区别**: - `final`:用于声明...
【知识点详解】 1. 关键字 final, finally, finalize 的理解 - final:final 用于声明类、方法或变量,表示不可变性。对于类,final 限制该类不能有子类;对于方法,final 方法不能被重写;对于变量,final 修饰的...
如果对象在可达性分析中没有与GC Root的引用链,那么此时就会被第一次标记并且进行一次筛选,筛选的条件是是否有必要执行finalize()方法。当对象没有覆盖finalize()方法或者已被虚拟机调用过,那么就认为是没必要的...