zoukankan      html  css  js  c++  java
  • 浅谈Java中的初始化和清理

    引言

      这篇文章我们主要介绍Java初始化和清理的相关内容,这些内容虽然比较基础,但是还是在这边做一个简单的总结,方便以后查阅。

    初始化过程

      Java尽力保证:所有变量在使用之前都会得到恰当的初始化(对于方法的局部变量,Java会以编译时错误的形式来提醒程序员进行初始化)。

      1、类数据成员的初始化

      类成员初始化过程是这样的:当我们实例化一个对象时,编译器会首先执行数据成员的初始化过程,然后在执行构造器。下面我们通过一个简单的例子来介绍下类数据成员的初始化过程。代码如下:

     1 class Sample {
     2     int value;
     3     
     4     public Sample() {
     5         this(0);
     6     }
     7     
     8     public Sample(int value) {
     9         this.value=value;
    10         System.out.println(this.value);
    11     }
    12     
    13     @Override
    14     public String toString() {
    15         return String.valueOf(this.value);
    16     }
    17 }
    18 
    19 public class PracClass {
    20     private int id;
    21     private String name;
    22     private static Sample sample=new Sample();
    23     
    24     public PracClass() {
    25         this(1,"defaltName");
    26     }
    27     
    28     public PracClass(int id,String name){
    29         this.id=id;
    30         this.name=name;
    31         System.out.println(this.id+" "+this.name);
    32     }
    33     
    34     @Override
    35     public String toString() {
    36         return this.id+" "+this.name+" SampleValue: "+sample;
    37     }
    38     
    39     public static void main(String[] args) {
    40         PracClass pracClass=new PracClass();
    41         System.out.println(pracClass);
    42     }
    43 }

      输出结果如下:

    1 0
    2 1 defaltName
    3 1 defaltName SampleValue: 0

      我们看到main函数实例化了一个PracClass对象。在PracClass类中其中有一个static对象sample。我们从输出结果中,可以看到编译器先执行了类成员数据的初始化过程(静态的和非静态的都是)。然后再执行对象的构造器。

      2、继承关系下的初始化过程

      我们来看一下存在继承关系下,类成员数据是如何初始化的,下面我们还是通过简单的例子来看一下:

     1 class Insect {
     2     private int i=9;
     3     protected int j;
     4     
     5     public Insect() {
     6         System.out.println("i="+i+","+j);
     7         j=20;
     8     }
     9     private static int x1=printInit("static Insect.x1 init");
    10     
    11     static int printInit(String s){
    12         System.out.println(s);
    13         return 16;
    14     }
    15 }
    16 
    17 
    18 public class PracClass extends Insect {
    19     private int k=printInit("Beetle.k init");
    20     public PracClass() {
    21         System.out.println("k="+k);
    22         System.out.println("j="+j);
    23     }
    24     private static int x2=printInit("Beetle.x2 init");
    25     
    26     public static void main(String[] args) {
    27         System.out.println("Beetle contructor");
    28         PracClass pracClass=new PracClass();
    29     }
    30 }

      我们来看一下运行结果:

    1 static Insect.x1 init
    2 Beetle.x2 init
    3 Beetle contructor
    4 i=9,0
    5 Beetle.k init
    6 k=16
    7 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方法不推荐使用,如果你想释放内存/资源,推荐显示的方法来释放分配的内存。

  • 相关阅读:
    Open vSwitch使用案例扩展实验
    hdoj-1233-还是畅通工程
    DS实验题 Floyd最短路径 & Prim最小生成树
    DS实验题 Missile
    Mininet实验 基于Mininet实现BGP路径挟持攻击实验
    Gift for GS5
    Bellman-Ford算法
    pox目录中的交换机mac地址学习模块 l2_multi源码
    Mininet实验 使用l2_multi模块寻找最短路径实验
    Ubuntu安装Flash
  • 原文地址:https://www.cnblogs.com/dreamGong/p/6561573.html
Copyright © 2011-2022 走看看