浅谈Java中的初始化和清理
引言
这篇文章我们主要介绍Java初始化和清理的相关内容,这些内容虽然比较基础,但是还是在这边做一个简单的总结,方便以后查阅。
初始化过程
Java尽力保证:所有变量在使用之前都会得到恰当的初始化(对于方法的局部变量,Java会以编译时错误的形式来提醒程序员进行初始化)。
1、类数据成员的初始化
类成员初始化过程是这样的:当我们实例化一个对象时,编译器会首先执行数据成员的初始化过程,然后在执行构造器。下面我们通过一个简单的例子来介绍下类数据成员的初始化过程。代码如下:
class Sample {
int value;
public Sample() {
this(0);
}
public Sample(int value) {
this.value=value;
System.out.println(this.value);
}
@Override
public String toString() {
return String.valueOf(this.value);
}
}
public class PracClass {
private int id;
private String name;
private static Sample sample=new Sample();
public PracClass() {
this(1,"defaltName");
}
public PracClass(int id,String name){
this.id=id;
this.name=name;
System.out.println(this.id+" "+this.name);
}
@Override
public String toString() {
return this.id+" "+this.name+" SampleValue: "+sample;
}
public static void main(String[] args) {
PracClass pracClass=new PracClass();
System.out.println(pracClass);
}
}
输出结果如下:
0
1 defaltName
1 defaltName SampleValue: 0
我们看到main函数实例化了一个PracClass对象。在PracClass类中其中有一个static对象sample。我们从输出结果中,可以看到编译器先执行了类成员数据的初始化过程(静态的和非静态的都是)。然后再执行对象的构造器。
2、继承关系下的初始化过程
我们来看一下存在继承关系下,类成员数据是如何初始化的,下面我们还是通过简单的例子来看一下:
class Insect {
private int i=9;
protected int j;
public Insect() {
System.out.println("i="+i+","+j);
j=20;
}
private static int x1=printInit("static Insect.x1 init");
static int printInit(String s){
System.out.println(s);
return 16;
}
}
public class PracClass extends Insect {
private int k=printInit("Beetle.k init");
public PracClass() {
System.out.println("k="+k);
System.out.println("j="+j);
}
private static int x2=printInit("Beetle.x2 init");
public static void main(String[] args) {
System.out.println("Beetle contructor");
PracClass pracClass=new PracClass();
}
}
我们来看一下运行结果:
static Insect.x1 init
Beetle.x2 init
Beetle contructor
i=9,0
Beetle.k init
k=16
j=20
当程序运行时,第一步就是去访问main方法,这时候加载器开始启动并且找出PracClass类的编译代码么。在这个加载过程中,编译器注意到它有一个基类,于是它继续进行加载基类(如果该基类还有其自身的基类,那么第二个基类就会被加载,如此类推)。这时候根基类中的static初始化,然后是下一个导出类。为什么要这样的?因为导出类的static初始化可能会依赖于基类成员是否被正确初始化。
这时候,必要的类都已经加载完毕。下面开始创建对象,这时候基类的实例变量初始化过程,然后执行基类构造器,然后执行导出类的实例变量初始化过程,然后是导出类的构造器。
清理过程
我们知道Java相比C++最大的一个差异之处在于Java是提供垃圾收集器的。但是垃圾收集器只回收那些使用new关键字分配的内存。对于不是使用new关键字来获取的内存,垃圾收集器是不知道如何释放的。Java为了应对这种情况允许在类中定义一个finalize的方法。它的工作原理是这样的:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize方法,并且在下一次垃圾回收时,才会真正的回收对象占用的内存。
通过上面的描述,我们知道finalize方法是不能作为通用的清理方法的。我们建议写一个显示的终止方法(类似于Stream中的close、Timer中的cancle等)那么在什么情况下才能使用finalize方法呢?下面两种情况可以使用finalize方法。
1、finalize方法作为安全网
我们显示的终结方法一般是使用try-finally结构来使用的。在finally方法内部调用显示的终止方法,可以保证即使在使用对象过程中发生异常,该终结方法还是会执行。
当对象的所有者忘记调用前面段落中建议的显示的终止方法时,finalize方法可以充当“安全网”的角色。虽然这样做不能保证终止方法会被及时的调用。但至少在无法通过调用显示终止方法来正常结束操作的情况下,迟一点释放关键资源总比不释放要好。如果我们在终结方法中发现资源还未被终止,那么应该在日志中记录一条警告,这样表示显示的终止方法可能没有被调用,此处需要进行修复。
2、与本地方法有关
如果在Java中使用JNI技术(即使用C/C++进行内存分配)。那么Java的垃圾收集器是无法进行内存回收的。这时候推荐使用显示的终止方法来释放这部分内存(你可以调用C/C++方法释放)。
简单总结
finalize方法不推荐使用,如果你想释放内存/资源,推荐显示的方法来释放分配的内存。
浅谈Java中的初始化和清理的更多相关文章
- 浅谈Java中静态初始化块跟非初始化块
众所周知在JAVA编程语言中有两种初始化块: 静态初始化块 非静态初始化块 他们到底有什么区别呢?今天就浅谈一下JAVA中静态初始化块和非静态初始化块的区别 静态初始化块 定义: ...
- 浅谈Java中的final关键字
浅谈Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...
- 浅谈Java中的equals和==(转)
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...
- 浅谈Java中的对象和引用
浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...
- 浅谈Java中的equals和==
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...
- 浅谈Java中的深拷贝和浅拷贝(转载)
浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...
- 浅谈Java中的深拷贝和浅拷贝
转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...
- 【转】浅谈Java中的hashcode方法(这个demo可以多看看)
浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...
- 【转】浅谈Java中的hashcode方法
哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native int hashCode(); 根据这个 ...
随机推荐
- jQuery事件处理(四)
看了几天,决定整理一下jQuery事件处理的整体设计思路 1.通过add方法给选中的元素注册事件处理程序(通过缓存系统将事件储存到cache,而不是绑定到元素上) a.在存储之前,会为事件处理程序增加 ...
- LeetCode 80 Remove Duplicates from Sorted Array II(移除数组中出现两次以上的元素)
题目链接:https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/#/description 给定一个已经排好序的数组 ...
- SQLite 3的中文读写
调用sqlite3_open函数默认创建的数据库encoding=UTF-8,执行sqlite3_exec时需要将对应的字符串转换为UTF-8格式多字节字符串.比如: sqlite3* db; aut ...
- Laya 图集动画
参考: 图集动画运用 一.准备素材 从爱给网找到几个素材 二.使用Laya的图集工具 菜单栏选择工具->图集打包工具,然后选择序列图所在的文件夹 生成了个.rec...说好的.atlas呢... ...
- SOA面向服务的架构
1.关于SOA的定义,目前主要有以下三个: 1)W3C的定义:SOA是一种应用程序架构,在这种架构中,所有功能都定义为独立的服务,这些服务带有定义明确的可调用接口,能够以定义好的顺序调用这些服务来形成 ...
- 【POJ2154】Color Pólya定理+欧拉函数
[POJ2154]Color 题意:求用$n$种颜色染$n$个珠子的项链的方案数.在旋转后相同的方案算作一种.答案对$P$取模. 询问次数$\le 3500$,$n\le 10^9,P\le 3000 ...
- [APP] Android 开发笔记 001-环境搭建与命令行创建项目
1. 安装JDK,SDK JDK http://www.oracle.com/technetwork/java/javase/downloads/index.html Android SDK http ...
- android 关于view的onTouch和onClick同时触发解决方案
extends:http://blog.sina.com.cn/s/blog_aa0bd5950101gbwt.html 做了一个悬浮窗,需要处理onTouch和onClick事件, 1 定义一个bo ...
- Unity3D笔记 英保通六 角色控制器
一.角色控制器 U3D有两种角色控制方式:Rigidbody刚体.角色控制器组件(胶囊体组件) 面试的题目中经常会遇到这个问题: CharacterController和Rigidbody的区别? 这 ...
- vue--获取监听获取radius的改变
做一个考试系统,单选题都是后台来的数据,所以一时间没有想到 @change这个方法: <template> <div id="Home"> <v-he ...