首页 | 资讯动态 | linux基础 | 系统管理 | 网络管理 | 编程开发 | linux数据库 | 服务器技术 | linux相关 | linux认证 | 嵌入式 | 下载中心 | 专题 | linux招聘 | 镜像站
OKLinux中文技术站
·设为首页
·加入收藏
·联系我们
系统管理: 中文环境 系统管理 桌面应用 内核技术 | Linux基础: 基础入门 安装配置 常用命令 经验技巧 软件应用 | Linux数据库: Mysql Postgre Oracle DB2 Sybase other
网络管理: 网络安全 网络应用 Linux服务器 环境配置 黑客安全 | 编程开发: PHP CC++ Python Perl Shell 嵌入式开发 java jsp | PHP技术: PHP基础 PHP技巧 PHP应用 PHP文摘
Linux资讯 Linux招聘 Linux专题 Apache | Linux相关: 硬件相关 Linux解决方案 Linux认证 企业应用 其它Unix | 相关下载: 资料下载 参考手册 开发工具 服务器类 软路由 其它
 技术搜索:
会员中心 注册会员 高级搜索  
  → 当前位置:首页>编程开发>java>Java基础>正文

全面解析Java中的类和对象的初始化过程

http://www.oklinux.cn  2008-01-20  来源: ccidnet baocl  会员收藏  游客收藏  【 】 

类的初始化和对象初始化是 JVM 治理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,非凡是从字节码和 JVM 层次来分析的文章更是鲜有所见。

  本文主要对类和对象初始化全过程进行分析,通过一个实际问题引入,将源代码转换成 JVM 字节码后,对 JVM 执行过程的要害点进行全面解析,并在文中穿插入了相关 JVM 规范和 JVM 的部分内部理论知识,以理论与实际结合的方式介绍对象初始化和类初始化之间的协作以及可能存在的冲突问题。

  问题引入

  近日我在调试一个枚举类型的解析器程序,该解析器是将数据库内一万多条枚举代码装载到缓存中,为了实现快速定位枚举代码和具体枚举类别的所有枚举元素,该类在装载枚举代码的同时对其采取两种策略建立内存索引。由于该类是一个公共服务类,在程序各个层面都会使用到它,因此我将它实现为一个单例类。这个类在我调整类实例化语句位置之前运行正常,但当我把该类实例化语句调整到静态初始化语句之前时,我的程序不再为我工作了。 下面是经过我简化后的示例代码:

  [清单一]

package com.ccb.framework.enums;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class CachingEnumResolver {
 //单态实例 一切问题皆由此行引起
 private static final CachingEnumResolver SINGLE_ENUM_RESOLVER = new CachingEnumResolver();
 /*MSGCODE->Category内存索引*/
 private static Map CODE_MAP_CACHE;
 static {
  CODE_MAP_CACHE = new HashMap();
  //为了说明问题,我在这里初始化一条数据
  CODE_MAP_CACHE.put("0","北京市");
 }
 //private, for single instance
 private CachingEnumResolver() {
  //初始化加载数据 引起问题,该方法也要负点责任
  initEnums();
 }
 /** * 初始化所有的枚举类型 */
 public static void initEnums() {
  // ~~~~~~~~~问题从这里开始暴露 ~~~~~~~~~~~//
  if (null == CODE_MAP_CACHE) {
   System.out.println("CODE_MAP_CACHE为空,问题在这里开始暴露.");
   CODE_MAP_CACHE = new HashMap();
  }
  CODE_MAP_CACHE.put("1", "北京市");
  CODE_MAP_CACHE.put("2", "云南省");
  //..... other code...
 }
 public Map getCache() {
  return Collections.unmodifiableMap(CODE_MAP_CACHE);
 }
 /** * 获取单态实例 * * @return */
 public static CachingEnumResolver getInstance() {
  return SINGLE_ENUM_RESOLVER;
 }
 public static void main(String[] args) {
  System.out.println(CachingEnumResolver.getInstance().getCache());
 }
}

  想必大家看了上面的代码后会感觉有些茫然,这个类看起来没有问题啊,这的确属于典型的饿汉式单态模式啊,怎么会有问题呢?

  是的,他看起来的确没有问题,可是假如将他 run 起来时,其结果是他不会为你正确 work。运行该类,它的执行结果是:

  [清单二]

  CODE_MAP_CACHE为空,问题在这里开始暴露.{0=北京市}

  我的程序怎么会这样?为什么在 initEnum() 方法里 CODE_MAP_CACHE 为空?为什么我输出的 CODE_MAP_CACHE 内容只有一个元素,其它两个元素呢????!!

  看到这里,假如是你在调试该程序,你此刻一定觉得很希奇,难道是我的 Jvm 有问题吗?非也!假如不是,那我的程序是怎么了?这绝对不是我想要的结果。可事实上无论怎么修改 initEnum() 方法都无济于事,起码我最初是一定不会怀疑到问题可能出在创建 CachingEnumResolver 实例这一环节上。正是因为我太相信我创建 CachingEnumResolver 实例的方法,加之对 Java 类初始化与对象实例化底层原理理解有所偏差,使我为此付出了三、四个小时--约半个工作日的大好青春。

  那么问题究竟出在哪里呢?为什么会出现这样的怪事呢?在解决这个问题之前,先让我们来了解一下JVM的类和对象初始化的底层机制。

  类的生命周期

图展示的是类生命周期流向;在本文里,我只打算谈谈类的"初始化"以及"对象实例化"两个阶段。

  类初始化

  类"初始化"阶段,它是一个类或接口被首次使用的前阶段中的最后一项工作,本阶段负责为类变量赋予正确的初始值。

  Java 编译器把所有的类变量初始化语句和类型的静态初始化器通通收集到 方法内,该方法只能被 Jvm 调用,专门承担初始化工作。

  除接口以外,初始化一个类之前必须保证其直接超类已被初始化,并且该初始化过程是由 Jvm 保证线程安全的。另外,并非所有的类都会拥有一个 () 方法,在以下条件中该类不会拥有 () 方法:

  该类既没有声明任何类变量,也没有静态初始化语句;该类声明了类变量,但没有明确使用类变量初始化语句或静态初始化语句初始化;该类仅包含静态 final 变量的类变量初始化语句,并且类变量初始化语句是编译时常量表达式。
对象初始化

  在类被装载、连接和初始化,这个类就随时都可能使用了。对象实例化和初始化是就是对象生命的起始阶段的活动,在这里我们主要讨论对象的初始化工作的相关特点。

  Java 编译器在编译每个类时都会为该类至少生成一个实例初始化方法--即 "()" 方法。此方法与源代码中的每个构造方法相对应,假如类没有明确地声明任何构造方法,编译器则为该类生成一个默认的无参构造方法,这个默认的构造器仅仅调用父类的无参构造器,与此同时也会生成一个与默认构造方法对应的 "()" 方法.

  通常来说,() 方法内包括的代码内容大概为:调用另一个 () 方法;对实例变量初始化;与其对应的构造方法内的代码。 假如构造方法是明确地从调用同一个类中的另一个构造方法开始,那它对应的

共3页: 上一页 1 [2] [3] 下一页

上一篇:EJB 3.0 的新规范概览及其未来发展方向   下一篇:一个非常有趣的使用spring框架AOP例子


收藏于收藏夹】 【评论】 【推荐】 【打印】 【关闭
相关文档
·一个非常有趣的使用spring框架AOP例子
·EJB 3.0 的新规范概览及其未来发展方向
·JAVA高级--Socket编程中的一个秘密类
·Java高级:怎样读取和处理XML的配置文件
·【Java语言深入】java 中线程概念描述
·Hibernate编写通用数据库操作代码演示
·通过JDBC连接oracle数据库的十大技巧
·JAVA企业应用:软件工程之Java实现策略
·Java高级:J2ME平台中几个重要概念的说明
·【开发框架】struts标签使用举例-logic
·J2SE综合介绍:泛型类型的子类及通配符使用
·JFreeChart 如何设置水平和垂直渐变背景
·用JavaBean编写SQLServer数据库连接类
·Hibernate配置文件中的映射元素详解
·spring 2.0自定义xml 标记 (二 如何实现)
·Webwork的validation校验框架实例详解
发表评论
密码: 匿名评论
评论内容:

(不超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规)
 
  最新文档
·Java入门:状态对象--数据库的替代者
·Java语言怎样调用外部应用程序
·Java语言深入--关于Java语言的内存泄漏
·JSP/Servlet/JSF:Servlet/JSP配置详解
·进阶-怎样使用AJAX进行WEB应用程序开发
·基础:J2ME程序开发之新手入门九大要点
·Java入门--Java语言接口与继承的本质
·JAVA进阶--如何提升JSP应用程序的效率
·对Java中四种XML解析技术之不完全测试
·编写高级 JScript应用代码
·JSP/Servlet/JSF--对标签库的深入研究
·Java入门--关于字符串分割的两种方法
  阅读排行
·使用AJAX技术实现网页无闪自动局部刷新
·快速教您Apache Tomcat SSL的配置
·Java语言深入--java调用C/C 的过程
·用JSP JavaScript打造二级级联下拉菜单
·JAVA进阶--线程运行栈信息的获取讲解
·使用WEBWORK实现文件上传方法实例详解
·J2SE综合--JAVA实现把汉字转化成拼音
·一个非常有趣的使用spring框架AOP例子
·关于java中相对路径,绝对路径问题总结
·高级:lucene全文检索应用示例及代码简
·详细讲解Struts构架中action的跳转大全
·Hibernate配置文件中的映射元素详解
·在Weblogic上配置JMS服务的方法
·对Java中四种XML解析技术之不完全测试
·数据库相关:小结Hibernate的查询方式
网摘收藏: