- 浏览: 589081 次
- 来自: 北京
文章分类
最新评论
-
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 2130Cassandra vs HBaseBy Vaibhav Pu ... -
Slope one:简单高效的推荐算法
2011-03-31 17:16 2715推荐系统最早在亚马逊的网站上应用,根据以往用户的购买行为, ... -
Hive 与 Hbase 的简单区别
2011-03-28 11:10 4171Hive是為簡化編寫MapReduce程序而生的,使用MapR ... -
Java对象缓存系统的实现,实现了LRU算法,并可以进行集群同步
2009-08-05 17:32 3711LRU算法实现: package com.javaeye.x ... -
Unsupported major.minor version 49.0
2009-07-14 16:03 1548http://www.blogjava.net/Unmi/ar ... -
Apache Commons Logging 是如何决定使用哪个日志实现类的
2009-07-14 16:01 1685http://www.blogjava.net/Unmi/ar ... -
Spring Quartz 任务调度
2009-07-07 10:22 2219要执行的任务类:CronTask pa ... -
利用java.util.concurrent包实现多线程开发
2009-06-23 16:09 2600有一个网站列表,我们分别使用单线程和多线程来测试这个网站是否允 ... -
Ngnix初探
2009-06-15 17:03 3220Nginx是什么? ... -
使用eclipse生成文档 javadoc
2009-06-15 10:20 14111,在项目列表中按右键,选择Export(导出),然后在Exp ... -
Java 日期类操作
2009-06-11 14:43 2296java之中操作日期的类分别为: #系统的日期时间类 ... -
留个记号。
2009-06-10 16:01 1025Comparable Comparator具体区别 h ... -
Java中java.io.Serializable接口的应用
2009-06-10 10:33 2551在Java中java.io.Serializable 用于实现 ... -
Java中的克隆功能的应用
2009-06-09 13:30 1686在JAVA中对象的克隆有的时候是必要的,克隆分两种:浅克隆、深 ... -
判断SQL注入的字符
2009-06-08 13:13 1443判断SQL注入的字符 public static bo ... -
ThreadLocal的设计与使用(原理篇)
2009-06-05 17:17 1087在jdk1.2推出时开始支持java.lang.ThreadL ... -
Nagios介绍
2009-05-26 13:33 1682系统管理员如何能够监视大量的机器和服务以便提前解决问题防止人们 ... -
Memecached实现缓存系统搭建。
2009-05-25 17:51 28451.在windows系统或Linux系统上安装memecach ... -
Java动态代理实现。
2009-05-25 13:33 951HelloWorld.java 接口文件 public i ... -
Java回调函数的实现方式。
2009-05-14 15:13 1756接口Callback类 public interface ...
相关推荐
JAVA类加载机制:探索虚拟世界的大门
### Java类动态加载机制在铁路互联网售票中的设计与实现 #### 概述 随着铁路互联网售票系统的广泛应用,其面临着越来越高的并发访问压力。为解决这一问题,系统采用分布式内存数据库集群来存储和处理如余票查询、...
本次实验的主要目的是深入理解Java虚拟机(JVM)中的类加载机制。通过实践操作,掌握类的加载、连接与初始化过程,了解不同类型的类加载器及其工作原理,学会创建自定义的类加载器,并对类的卸载有所认识。实验将结合...
Java深度历险,让我们一起探索Java类的加载机制,这是Java高级编程中至关重要的一部分,尤其对于有基础的Java开发者来说,深入理解这个话题能够提升你的编程能力,优化系统性能,以及更好地解决运行时问题。...
3. **健壮性**:Java设计时注重安全性和健壮性,提供了垃圾回收机制自动管理内存,减少了内存泄漏和其他内存相关问题。 4. **多线程**:Java内置了对多线程编程的支持,允许开发者创建同时运行的多个线程。 5. **...
Java Agent是Java平台的一个强大特性,它允许开发者在运行时对JVM中的类进行操作,包括类的加载、修改和卸载。这种能力使得Java Agent成为实现各种高级功能的理想选择,如监控、性能分析、安全增强等。本文将详细...
Java反射机制是Java编程语言...总之,Java反射机制是Java语言中一个强大的工具,它增强了Java的灵活性,允许开发者在运行时探索和操作类的内部结构。尽管反射带来了诸多便利,但也需要合理使用,以平衡灵活性和稳定性。
总的来说,Java 反射机制是 Java 动态性的一个重要体现,它提供了在运行时探索和操作类的能力,使得代码更加灵活,但也需要开发者对潜在的风险有足够的认识。通过合理使用反射,开发者可以构建出更强大、更适应变化...
### Java反射机制详解 #### 一、Java反射机制概述 在深入探讨Java反射机制之前,我们首先...在后续的文章中,我们将更深入地探索Java反射机制的各个方面,包括运行时元数据访问以及在运行时修改和构建新类的方法。
类加载器的学习是深入理解Java运行机制的关键,尤其对于系统级开发和框架设计而言更是如此。本文将主要围绕“黑马程序员------类加载器学习注意点”展开,探讨一些关键知识点。 首先,我们需要理解类加载器的基本...
### 浅谈Java中的四个核心概念 随着信息技术的飞速发展与互联网的普及,Java作为一门面向...这些概念不仅帮助开发者更好地编写高效、可靠的Java程序,也为进一步探索Java生态系统中的其他高级特性打下了坚实的基础。
热更新的基本原理是利用JVM的类加载机制。在Java中,类是由ClassLoader加载的,当一个类被加载后,如果该类的.class文件被修改,ClassLoader可以重新加载这个修改后的类,从而实现运行时的代码更新。但是,需要注意...
总之,Java反射机制为开发者提供了强大的工具,使得程序在运行时能够对自身进行深入的探索和操作。然而,使用时也需谨慎,权衡其带来的灵活性与潜在的性能损失和安全风险。在实际开发中,合理运用反射可以大大提高...
### JAVA杂谈:深入探索Java的核心机制与实践 #### 动态加载机制解析 Java的动态加载机制是其面向对象编程(OOP)理念的核心体现之一,它使得Java能够在运行时根据需要加载类,而非在程序启动之初加载所有类。这种...
Java反射机制是Java编程语言中...总之,Java反射机制是Java语言灵活性的体现,它提供了一种强大的工具,允许程序员在运行时探索和操纵类和对象。但同时,也需注意其潜在的风险和性能影响,合理地在项目中应用反射技术。
例如,如何解释类文件在内存中的加载和执行、对象的垃圾回收机制等,这些知识点对学生的理解JAVA的跨平台特性和安全性产生了重要影响。 本文探索了JAVA虚拟机在JAVA课程教学中的应用,强调了JAVA虚拟机在JAVA技术体...
Java 反射机制是Java语言中一种强大的工具,它允许程序在运行时探索和操作类、接口、对象的内部结构。反射机制的核心在于Java提供的`java.lang.reflect`包,其中包括了`Class`、`Field`、`Method`、`Constructor`和`...
### 探索Java虚拟机的心脏:字节码执行全解析 #### Java语言概览 Java自1995年由Sun Microsystems(现归Oracle所有)发布以来,已成为全球范围内广泛应用的编程语言。作为一种面向对象的语言,Java将现实世界中的...
### 深入Java虚拟机最新版:执行引擎与类加载机制详解 #### 执行引擎:一次探索之旅 Java虚拟机(JVM)的核心组件之一就是执行引擎,它负责将字节码转换为机器指令执行。在《深入Java虚拟机最新版》这本书中,我们...
Java反射机制是Java编程语言中一个强大的工具,它允许程序在运行时动态地获取类的信息并操作类的对象。反射机制的核心在于java.lang.reflect包中的API,主要包括Class类、Constructor类、Method类和Field类。以下是...