java 类中变量,方法加载顺序和造成的问题。

我使用 java 有也有很长时间了,但是,对于java的一些基本概念也没有搞清楚,

所以需要再学习下,

 

java 的变量方法加载顺序,

java 类有 类变量,成员变量,static 块,构造函数,在类初始化,和实例初始化的时候,都做了什么,和怎么做的呢?

如果有子类继承父类,还有 override,那情况又怎么样呢?

带着这个问题,我们往下看,

 

1, 我最近碰到一个问题,像这样的,

 

/**

 * as util class, it hold some critical resource, e.g. db connection, other service connection,

 * we make it as singleton,

 */

public class MyUtil { 

  private static MyUtil instance = new MyUtil();

  private static logger = new Log4jLogger();

  

  // make it as private, prevent crete instance out of this class.

  private MyUtil {

    doInit();

  }

 

  private void doInit() {

    boolean result = false;

    //do some logic,

    ......

    if (!result) {

      logger.error("there're error in init"); // here, will cause error,

    }

  }

 

  public MyUtil getInstance() {

    return instance;

  }

 

  public void doSomeLogic() {

    // do some logic, ...

  }

}

 

/**

 * in this class, we get singleton of MyUtil class, and call method, doSomeLogic().

 *

 **/

public class MyCode() {

 

    void oneMethod {

        MyUtil.getInstance().doSomeLogic();

    }

}

 

in above code, we always get NullPointException,

after debug, we found that, MyUtil.getInstance() is null,

 

after still checking, we found that,

InstantiationException

 

we still dig it out,

while we init the class, in doInit method, logger is null,

 

然后,我又了解了,java 类的加载机制,

 

2, java 类的变量和方法加载机制,

 

首先是,父类的 static 变量和 static 块。

接着是,子类的 static 变量和 static 块,

再接着是,

            父类的 成员变量和 构造函数,

最后是,

            子类的 成员变量和 构造函数,

 

 

在我的这个真实例子中,问题就出在,我有两个 static variable, instance 和 logger,

他们加载顺序,jvm 是不保证的,

而且 instance static 变量的初始化,还用了 construct 方法,

而在 construct 方法中,调用 doInit(), 方法中,用 logger 的时候,可能还没有被初始化,

null point exception, 造成class instantiation exception,

 

后来的调用,null point exception,

 

这就是这个问题的原因, 

怎么解决呢,知道了原因就比较好了。

 

3, 解决办法

 

public class MyUtil {

 

private static MyUtil instance; 

private static logger; 

 

// make sure logger is init, before instance.

static {

    logger = new Log4jLogger();

    instance = new MyUtil();

}

 

// make it as private, prevent crete instance out of this class.

private MyUtil {

    doInit();

}

 

......

 

}

 

static 变量不赋值,然后加一个 static 块,保证 logger 在 instance 之前,被赋值。

 

4, 然后有以下总结,

 

就是

    static 变量要什么时候赋值,特别是和 singleton搅在一起的时候,特别要当心,

比如,下面的例子。

 

class MyTest() {

  // the initial default value.

  private static theVal = 1;

 

  public MyTest() {

     // get value from configuration,

     theVal = ConfigUtil.getValue();

  }

 

}

 

这个 例子是工作的,能读到 configuration value,

因为是,先执行 static variable 初始化,然后执行 构造函数的。

 

但是,下面的一个,就要当心了。

 

class MyTest() {

  // the initial default value.

  private static theVal = 1;

  private static instance = new MyTest();

 

  private MyTest() {

     // get value from configuration,

     theVal = ConfigUtil.getValue();

  }

 

}

 

这时候,就不明白先执行,

theVal = 1, 还是 theVal = ConfigUtil.getValue(); 了,

 

还有,

static 变量之间,和 static 块,都不保证,先后执行顺序的。

不过 static 块中的语句,是保证的。

 

这个,我上次就碰到了一个问题。hehe.

 

5, 另外的想法,

 

对于 singleton 的类,我们是否可以去掉 static, 全部改成 成员变量,

因为,他本身就是,唯一的,可有什么问题?

 

static, 和 singleton 两者取其一,消除他们之间的影响。

 

6, 网上参考资料

 

http://ilexes.blog.51cto.com/705330/268868

http://www.360doc.com/content/07/0915/17/44521_746650.shtml

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值