- 浏览: 578516 次
- 来自: 北京
文章分类
最新评论
-
lidi2011:
很通俗易懂的文章,很形象。
同步synchronized方法和代码块 -
inuyasha027:
领教了,谢谢。
Hadoop安装, Hive 安装。 -
xbmujfly:
好文 ,本人发现晚了
学习笔记 - java.util.concurrent 多线程框架 -
hanazawakana:
学习学习!
ANT-build.xml文件详解 -
david.org:
似乎还忽略一点,那就是cassandra不同数据中心的同步,H ...
Cassandra Vs HBase
java虚拟【java.dll】存在于JRE目中下的bin目录下
D:\Program Files\Java\jre1.5.0_13\bin\java.dll【我机器上的目录你的机器可能与此略有不同】
1. 预先加载与依需求加载
Java 运行环境为了优化系统,提高程序的执行速度,在 JRE 运行的开始会将 Java 运行所需要的基本类采用预先加载( pre-loading )的方法全部加载要内存当中,因为这些单元在 Java 程序运行的过程当中经常要使用的,主要包括 JRE 的 rt.jar 文件里面所有的 .class 文件。
当 java.exe 虚拟机开始运行以后,它会找到安装在机器上的 JRE 环境,然后把控制权交给 JRE , JRE 的类加载器会将 lib 目录下的 rt.jar 基础类别文件库加载进内存,这些文件是 Java 程序执行所必须的,所以系统在开始就将这些文件加载,避免以后的多次 IO 操作,从而提高程序执行效率。
图( 2 )我们可以看到多个基础类被加载, java.lang.Object,java.io.Serializable 等等。
图( 2 )
相对于预先加载,我们在程序中需要使用自己定义的类的时候就要使用依需求加载方法( load-on-demand ),就是在 Java 程序需要用到的时候再加载,以减少内存的消耗,因为 Java 语言的设计初衷就是面向嵌入式领域的。
在这里还有一点需要说明的是, JRE 的依需求加载究竟是在什么时候把类加载进入内部的呢?
我们在定义一个类实例的时候,比如 TestClassA testClassA ,这个时候 testClassA 的值为 null ,也就是说还没有初始化,没有调用 TestClassA 的构造函数,只有当执行 testClassA = new TestClassA() 以后, JRE 才正真把 TestClassA 加载进来。
2. 隐式加载和显示加载
Java 的加载方式分为隐式加载( implicit )和显示加载( explicit ),上面的例子中就是用的隐式加载的方式。所谓隐式加载就是我们在程序中用 new 关键字来定义一个实例变量, JRE 在执行到 new 关键字的时候就会把对应的实例类加载进入内存。隐式加载的方法很常见,用的也很多, JRE 系统在后台自动的帮助用户加载,减少了用户的工作量,也增加了系统的安全性和程序的可读性。
相对于隐式加载的就是我们不经常用到的显示加载。所谓显示加载就是有程序员自己写程序把需要的类加载到内存当中,下面我们看一段程序:
class TestClass{
public void method(){
System.out.println("TestClass-method");
}
}
public class CLTest {
public static void main(String args[]) {
try{
Class c = Class.forName("TestClass");
TestClass object = (TestClass)c.newInstance();
object.method();
}catch(Exception e){
e.printStackTrace();
}
}
}
我们通过 Class 类的 forName (String s) 方法把自定义类 TestClass 加载进来,并通过 newInstance ()方法把实例初始化。事实上 Class 类还很多的功能,这里就不细讲了,有兴趣的可以参考 JDK 文档。
Class 的 forName() 方法还有另外一种形式: Class forName(String s, boolean flag, ClassLoader classloader) , s 表示需要加载类的名称, flag 表示在调用该函数加载类的时候是否初始化静态区, classloader 表示加载该类所需的加载器。
forName (String s) 是默认通过 ClassLoader.getCallerClassLoader() 调用类加载器的,但是该方法是私有方法,我们无法调用,如果我们想使用 Class forName(String s, boolean flag, ClassLoader classloader) 来加载类的话,就必须要指定类加载器,可以通过如下的方式来实现:
Test test = new Test();//Test 类为自定义的一个测试类;
ClassLoader cl = test. getClass().getClassLoader();
// 获取 test 的类装载器;
Class c = Class.forName("TestClass", true, cl);
因为一个类要加载就必需要有加载器,这里我们是通过获取加载 Test 类的加载器 cl 当作加载 TestClass 的类加载器来实现加载的。
3. 自定义类加载机制
之前我们都是调用系统的类加载器来实现加载的,其实我们是可以自己定义类加载器的。利用 Java 提供的 java.net.URLClassLoader 类就可以实现。下面我们看一段范例:
try{
URL url = new URL("file:/d:/test/lib/");
URLClassLoader urlCL = new URLClassLoader(new URL[]{url});
Class c = urlCL.loadClass("TestClassA");
TestClassA object = (TestClassA)c.newInstance();
object.method();
}catch(Exception e){
e.printStackTrace();
}
我们通过自定义的类加载器实现了 TestClassA 类的加载并调用 method ()方法。分析一下这个程序:首先定义 URL 指定类加载器从何处加载类, URL 可以指向网际网络上的任何位置,也可以指向我们计算机里的文件系统 ( 包含 JAR 文件 ) 。上述范例当中我们从 file:/d:/test/lib/ 处寻找类;然后定义 URLClassLoader 来加载所需的类,最后即可使用该实例了。
4. 类加载器的阶层体系
讨论了这么多以后,接下来我们仔细研究一下 Java 的类加载器的工作原理:
当执行 java ***.class 的时候, java.exe 会帮助我们找到 JRE ,接着找到位于 JRE 内部的 jvm.dll ,这才是真正的 Java 虚拟机器 , 最后加载动态库,激活 Java 虚拟机器。虚拟机器激活以后,会先做一些初始化的动作,比如说读取系统参数等。一旦初始化动作完成之后,就会产生第一个类加载器―― Bootstrap Loader , Bootstrap Loader 是由 C++ 所撰写而成,这个 Bootstrap Loader 所做的初始工作中,除了一些基本的初始化动作之外,最重要的就是加载 Launcher.java 之中的 ExtClassLoader ,并设定其 Parent 为 null ,代表其父加载器为 BootstrapLoader 。然后 Bootstrap Loader 再要求加载 Launcher.java 之中的 AppClassLoader ,并设定其 Parent 为之前产生的 ExtClassLoader 实体。这两个加载器都是以静态类的形式存在的。这里要请大家注意的是, Launcher$ExtClassLoader.class 与 Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加载,所以 Parent 和由哪个类加载器加载没有关系。
下面的图形可以表示三者之间的关系:
父类
父类
载入
载入
BootstrapLoader
PARENT
AppClassLoader
PARENT
ExtClassLoader
这三个加载器就构成我们的 Java 类加载体系。他们分别从以下的路径寻找程序所需要的类:
BootstrapLoader : sun.boot.class.path
ExtClassLoader: java.ext.dirs
AppClassLoader: java.class.path
这三个系统参量可以通过 System.getProperty() 函数得到具体对应的路径。大家可以自己编程实现查看具体的路径。
实现自己的类加载器
使用了反射的方法来调用自定义类加载器加载上来的类。
参考:http://www.blogjava.net/William/archive/2006/08/25/65804.html
D:\Program Files\Java\jre1.5.0_13\bin\java.dll【我机器上的目录你的机器可能与此略有不同】
1. 预先加载与依需求加载
Java 运行环境为了优化系统,提高程序的执行速度,在 JRE 运行的开始会将 Java 运行所需要的基本类采用预先加载( pre-loading )的方法全部加载要内存当中,因为这些单元在 Java 程序运行的过程当中经常要使用的,主要包括 JRE 的 rt.jar 文件里面所有的 .class 文件。
当 java.exe 虚拟机开始运行以后,它会找到安装在机器上的 JRE 环境,然后把控制权交给 JRE , JRE 的类加载器会将 lib 目录下的 rt.jar 基础类别文件库加载进内存,这些文件是 Java 程序执行所必须的,所以系统在开始就将这些文件加载,避免以后的多次 IO 操作,从而提高程序执行效率。
图( 2 )我们可以看到多个基础类被加载, java.lang.Object,java.io.Serializable 等等。
图( 2 )
相对于预先加载,我们在程序中需要使用自己定义的类的时候就要使用依需求加载方法( load-on-demand ),就是在 Java 程序需要用到的时候再加载,以减少内存的消耗,因为 Java 语言的设计初衷就是面向嵌入式领域的。
在这里还有一点需要说明的是, JRE 的依需求加载究竟是在什么时候把类加载进入内部的呢?
我们在定义一个类实例的时候,比如 TestClassA testClassA ,这个时候 testClassA 的值为 null ,也就是说还没有初始化,没有调用 TestClassA 的构造函数,只有当执行 testClassA = new TestClassA() 以后, JRE 才正真把 TestClassA 加载进来。
2. 隐式加载和显示加载
Java 的加载方式分为隐式加载( implicit )和显示加载( explicit ),上面的例子中就是用的隐式加载的方式。所谓隐式加载就是我们在程序中用 new 关键字来定义一个实例变量, JRE 在执行到 new 关键字的时候就会把对应的实例类加载进入内存。隐式加载的方法很常见,用的也很多, JRE 系统在后台自动的帮助用户加载,减少了用户的工作量,也增加了系统的安全性和程序的可读性。
相对于隐式加载的就是我们不经常用到的显示加载。所谓显示加载就是有程序员自己写程序把需要的类加载到内存当中,下面我们看一段程序:
class TestClass{
public void method(){
System.out.println("TestClass-method");
}
}
public class CLTest {
public static void main(String args[]) {
try{
Class c = Class.forName("TestClass");
TestClass object = (TestClass)c.newInstance();
object.method();
}catch(Exception e){
e.printStackTrace();
}
}
}
我们通过 Class 类的 forName (String s) 方法把自定义类 TestClass 加载进来,并通过 newInstance ()方法把实例初始化。事实上 Class 类还很多的功能,这里就不细讲了,有兴趣的可以参考 JDK 文档。
Class 的 forName() 方法还有另外一种形式: Class forName(String s, boolean flag, ClassLoader classloader) , s 表示需要加载类的名称, flag 表示在调用该函数加载类的时候是否初始化静态区, classloader 表示加载该类所需的加载器。
forName (String s) 是默认通过 ClassLoader.getCallerClassLoader() 调用类加载器的,但是该方法是私有方法,我们无法调用,如果我们想使用 Class forName(String s, boolean flag, ClassLoader classloader) 来加载类的话,就必须要指定类加载器,可以通过如下的方式来实现:
Test test = new Test();//Test 类为自定义的一个测试类;
ClassLoader cl = test. getClass().getClassLoader();
// 获取 test 的类装载器;
Class c = Class.forName("TestClass", true, cl);
因为一个类要加载就必需要有加载器,这里我们是通过获取加载 Test 类的加载器 cl 当作加载 TestClass 的类加载器来实现加载的。
3. 自定义类加载机制
之前我们都是调用系统的类加载器来实现加载的,其实我们是可以自己定义类加载器的。利用 Java 提供的 java.net.URLClassLoader 类就可以实现。下面我们看一段范例:
try{
URL url = new URL("file:/d:/test/lib/");
URLClassLoader urlCL = new URLClassLoader(new URL[]{url});
Class c = urlCL.loadClass("TestClassA");
TestClassA object = (TestClassA)c.newInstance();
object.method();
}catch(Exception e){
e.printStackTrace();
}
我们通过自定义的类加载器实现了 TestClassA 类的加载并调用 method ()方法。分析一下这个程序:首先定义 URL 指定类加载器从何处加载类, URL 可以指向网际网络上的任何位置,也可以指向我们计算机里的文件系统 ( 包含 JAR 文件 ) 。上述范例当中我们从 file:/d:/test/lib/ 处寻找类;然后定义 URLClassLoader 来加载所需的类,最后即可使用该实例了。
4. 类加载器的阶层体系
讨论了这么多以后,接下来我们仔细研究一下 Java 的类加载器的工作原理:
当执行 java ***.class 的时候, java.exe 会帮助我们找到 JRE ,接着找到位于 JRE 内部的 jvm.dll ,这才是真正的 Java 虚拟机器 , 最后加载动态库,激活 Java 虚拟机器。虚拟机器激活以后,会先做一些初始化的动作,比如说读取系统参数等。一旦初始化动作完成之后,就会产生第一个类加载器―― Bootstrap Loader , Bootstrap Loader 是由 C++ 所撰写而成,这个 Bootstrap Loader 所做的初始工作中,除了一些基本的初始化动作之外,最重要的就是加载 Launcher.java 之中的 ExtClassLoader ,并设定其 Parent 为 null ,代表其父加载器为 BootstrapLoader 。然后 Bootstrap Loader 再要求加载 Launcher.java 之中的 AppClassLoader ,并设定其 Parent 为之前产生的 ExtClassLoader 实体。这两个加载器都是以静态类的形式存在的。这里要请大家注意的是, Launcher$ExtClassLoader.class 与 Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加载,所以 Parent 和由哪个类加载器加载没有关系。
下面的图形可以表示三者之间的关系:
父类
父类
载入
载入
BootstrapLoader
PARENT
AppClassLoader
PARENT
ExtClassLoader
这三个加载器就构成我们的 Java 类加载体系。他们分别从以下的路径寻找程序所需要的类:
BootstrapLoader : sun.boot.class.path
ExtClassLoader: java.ext.dirs
AppClassLoader: java.class.path
这三个系统参量可以通过 System.getProperty() 函数得到具体对应的路径。大家可以自己编程实现查看具体的路径。
实现自己的类加载器
import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.lang.reflect.Method; public class Test { static { System.out.println("\n\n.......... Test class\n\n"); } public static void main(String[] args) throws Exception{ URL url = null; try { url = new URL("file:/d:/temp/"); } catch (Exception e) { e.printStackTrace(); } URLClassLoader cl = new URLClassLoader(new URL[]{url}); Class clz = cl.loadClass("Name"); Method method = clz.getMethod("sayHello5"); method.invoke(clz.newInstance()); } }
使用了反射的方法来调用自定义类加载器加载上来的类。
public class Name { public Name(){ System.out.println("Name Class"); } static { System.out.println("This is a static area"); } public void sayHello(){ System.out.println("Name Class Say Hello"); } }
参考:http://www.blogjava.net/William/archive/2006/08/25/65804.html
发表评论
-
Cassandra Vs HBase
2011-03-31 17:27 2068Cassandra vs HBaseBy Vaibhav Pu ... -
Slope one:简单高效的推荐算法
2011-03-31 17:16 2658推荐系统最早在亚马逊的网站上应用,根据以往用户的购买行为, ... -
Hive 与 Hbase 的简单区别
2011-03-28 11:10 4124Hive是為簡化編寫MapReduce程序而生的,使用MapR ... -
Java对象缓存系统的实现,实现了LRU算法,并可以进行集群同步
2009-08-05 17:32 3648LRU算法实现: package com.javaeye.x ... -
Unsupported major.minor version 49.0
2009-07-14 16:03 1487http://www.blogjava.net/Unmi/ar ... -
Apache Commons Logging 是如何决定使用哪个日志实现类的
2009-07-14 16:01 1632http://www.blogjava.net/Unmi/ar ... -
Spring Quartz 任务调度
2009-07-07 10:22 2155要执行的任务类:CronTask pa ... -
利用java.util.concurrent包实现多线程开发
2009-06-23 16:09 2547有一个网站列表,我们分别使用单线程和多线程来测试这个网站是否允 ... -
Ngnix初探
2009-06-15 17:03 3141Nginx是什么? ... -
使用eclipse生成文档 javadoc
2009-06-15 10:20 13661,在项目列表中按右键,选择Export(导出),然后在Exp ... -
Java 日期类操作
2009-06-11 14:43 2240java之中操作日期的类分别为: #系统的日期时间类 ... -
留个记号。
2009-06-10 16:01 975Comparable Comparator具体区别 h ... -
Java中java.io.Serializable接口的应用
2009-06-10 10:33 2480在Java中java.io.Serializable 用于实现 ... -
Java中的克隆功能的应用
2009-06-09 13:30 1601在JAVA中对象的克隆有的时候是必要的,克隆分两种:浅克隆、深 ... -
判断SQL注入的字符
2009-06-08 13:13 1396判断SQL注入的字符 public static bo ... -
ThreadLocal的设计与使用(原理篇)
2009-06-05 17:17 1027在jdk1.2推出时开始支持java.lang.ThreadL ... -
Nagios介绍
2009-05-26 13:33 1632系统管理员如何能够监视大量的机器和服务以便提前解决问题防止人们 ... -
Memecached实现缓存系统搭建。
2009-05-25 17:51 27841.在windows系统或Linux系统上安装memecach ... -
Java动态代理实现。
2009-05-25 13:33 891HelloWorld.java 接口文件 public i ... -
Java回调函数的实现方式。
2009-05-14 15:13 1713接口Callback类 public interface ...
相关推荐
JAVA类加载机制:探索虚拟世界的大门
JAVA类的加载、链接和初始化 11 JAVA类的加载 11 JAVA类的链接 12 JAVA类的初始化 13 创建自己的类加载器 14 参考资料 15 JAVA线程:基本概念、可见性与同步 16 JAVA线程基本概念 16 可见性 17 JAVA中的锁 18 JAVA...
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。...
│ Java面试题40.jQuery中页面加载完毕事件.mp4 │ Java面试题41.jQuery中Ajax和原生js实现Ajax的关系.mp4 │ Java面试题42.简单说一下html5.mp4 │ Java面试题43.简单说一下css3.mp4 │ Java面试题44.bootstrap的是...
Mark-Sweep)收集器和 G1(Garbage-First)收集器)、类加载机制,以及HotSpot VM 基于栈的架构模型和执行引擎(解释器的工作流程、JIT 编译器的工作流程、分层编译策略、热点探测功能)等技术。, 如果你对JVM 感...
详细介绍了JVM执行子系统的工作原理,包括类文件结构与字节码指令(Class类文件结构、JVM字节码指令简介)、JVM类加载机制(类加载器、类加载时机、类加载过程)、字节码执行引擎(运行时候的栈结构、方法调用、方法...
《Android开发艺术探索》是一本Android进阶类书籍,采用理论、源码和实践相结合的方式来阐述高水准的Android应用开发要点。《Android开发艺术探索》从三个方面来组织内容。第一,介绍Android开发者不容易掌握的一些...
具有自定义故事情节,战斗和探索的Java类。 60%完成 产品特点 通过加密的JSON保存游戏 自定义库存机制,怪物战斗,宝藏 用LibGDX Java构建 下载 从发布页面下载最新版本 克隆存储库并加载到IntelliJ IDEA或Eclipse...
14.4 JNI调用Java方法的流程 / 486 第15章 Android性能优化 / 489 15.1 Android的性能优化方法 / 490 15.1.1 布局优化 / 490 15.1.2 绘制优化 / 493 15.1.3 内存泄露优化 / 493 15.1.4 响应速度优化和...
本书是一本Android进阶类书籍,采用理论、源码和实践相结合的方式来阐述高水准的Android应用开发要点。本书从三个方面来组织内容。第一,介绍Android开发者不容易掌握的一些知识点;第二,结合Android源代码和应用层...
安卓java读取网页源码 AndroidStudy Android进阶内容整理 blog地址链接: 书籍: 1.Android群英传 2.Android艺术开发与探索 3.Android设计模式 第三方框架 详细使用步骤加源码解析:1.会使用 2.懂原理 3.框架源码...
安卓上用于加载的Webview视图窗口只是作为类浏览器而存在,在安卓上更是只能同时运行一个Webview。(2)跨域数据交互问题。不同的Webview之间无法共享数据。(3)页面自适应问题。页面难以兼容适应不同分辨率的设备...
NHibernate 之旅(3):探索查询之 NHibernate 查询语言(HQL)..............................17 NHibernate 中的查询方法 ......................................................................................18...
本书是Hadoop权威参考,程序员可从中探索如何分析海量数据集,管理员可以从中了解如何安装与运行Hadoop集群。 目录 第1章 初识Hadoop 数据!数据! 数据存储与分析 与其他系统相比 关系型数据库管理系统...
使用Pig和Wukong来探索10亿数量级边的 网络图 测量社区 每个人都在和我说话:Twitter回复关系图 (度)degree 对称链接 社区提取 附录A 安装Apache Hadoop 附录B Cloudera’s Distribution for Hadoop 附录C 准备...
淘宝在这一领域做了有效的探索和实践,Taobao File System(TFS)作为淘宝内部使用的分布式文件系统,针对海量小文件的随机读写访问性能做了特殊优化,承载着淘宝主站所有图片、商品描述等数据存储。 文章首先概括了...
asp.net 运行机制初探(httpModule加载) 利用反射来查看对象中的私有变量 关于反射中创建类型实例的两种方法 ASP.Net应用程序的多进程模型 NET委托:一个C#睡前故事 [推荐] - [原创] Microsoft .NET策略及框架概述 ...
解析提供了自己的推送消息机制,该机制的工作原理与Google Cloud Messaging(GCM)相同。 因此决定充分探索解析。 此应用是使用Android本地语言并以解析为后端来实现的。 应用程序的生命周期:当用户发送消息时,...