`
草帽当家的
  • 浏览: 25076 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
文章分类
社区版块
存档分类
最新评论

从JVM到RTTI

 
阅读更多
        这一切还要从CLASS文件说起。当我们在虚拟机上编写java文件时,虚拟机会动态地将java文件转换为以.class为后缀名的CLASS文件。那么这个ClASS文件又有什么作用呢?为什么我们删除java文件保留ClASS文件,在命令行中执行java filename程序仍能正常运行呢?

一、CLASS文件
        1、概述   
        Java编译器将Java源文件指令翻译成虚拟机能识别的字节码,这些机器码被储存在以.class为扩展名的CLASS文件中。CLASS文件是可以运行在任何支持Java虚拟机的硬件平台和操作系统上的二进制文件。每个CLASS文件都包含一个类或接口的定义和实现。CLASS文件是一个虚拟机的指令集,所有的这些指令都会被程序翻译成目标机器的机器语言。
        2、作用
        平台无关性:为Java程序提供独立于底层主机平台的二进制形式的服务。
        网络移动性: CLASS文件设计得紧凑,因此它们可以快速地在网络上传送。其次,由于Java程序是动态连接和动态扩展的,CLASS文件可以在需要的时候才下载。这个特点使得Java应用程序能够安排从网络上下载CLASS文件的时间,从而可以最大限度地减少终端用户的等待时间。
        3、链接
        所有的类都是在对其第一次使用,通过类加载器动态地加载到虚拟机中的。然而,类加载器加载的不是Java源文件,而是编译后的CLASS文件,从而可以看出——Java文件只是用户和虚拟机的交互,真正对虚拟机有意义的是CLASS文件,它参与了虚拟机与底层的交互

二、类加载器
        1、概述
        类加载机制不只是使用一个单一的类加载器,每个Java程序至少有三个类加载器,它们都是系统类加载器。用户也可以通过实现java.lang.ClassLoader实现自定义类加载器。
        2、JVM自带类加载器
        根类加载器(Bootstrap):使用c++编写,该加载器没有父加载器。它负责加载虚拟机的核心类库(典型地,来自rt.jar包下的类库)。根类加载器依赖于底层操作系统,属于虚拟机实现的一部分,它并没有实现java.lang.ClassLoader类。
        扩展类加载器(Extension):纯java代码编写,ClassLoader的子类,它的父加载器为根类加载器。它从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre\lib\ext子目录下加载类库。你可以将你要引进的jar文件放在该目录下,加载器不需要任何class path就可以找到它们的类库。
        系统类加载器或应用加载器(System):纯java代码编写,ClassLoader的子类,它的父加载器为扩展类加载器,它从环境变量classpath或系统属性java.class.path所指定的目录中加载类,它是用户自定义的类加载器的默认父加载器
        3、类的加载过程
        类的加载采用父类委托机制,这种机制能够更好的保障Java平台的安全性。在此委托机制中,除Java自带的根加载器外,其余的加载器都有且只有一个父加载器,如下层次图所示,当Java程序请求(your custom)loader加载(your custom)class时,loader首先委托自己的父加载器去加载class,若父加载器能完成,则由父加载器加载,否则由loader加载。(这种关系并非是继承关系,而是一种包装机制)。
       
        4、命名空间
        在Java中一个类通过认证的类全名来唯一的标识。认证的类全名包括包名和类名两部分组成。但是一个被加载到JVM中的类则通过类的全名和加载这个类的类记载器来唯一的标识。每个类加载器都有自己的命名空间,命名空间由该加载器和所有的父加载器所加载的类组成。在同一个命名空间不会出现类的完整名字(包括包名)相同的两个类;在不同的命名空间有可能出现完整的名字包括包名相同的两个类。
        5、运行时包
        由同一个类加载器加载的属于相同包的类组成了运行时包,决定两个类是不是属于同一个运行时包,不仅要看它们的包名是否相同,还要看定义类加载器是否相同,只有属于同一个运行时包的类才能互相访问包可见的类和类成员,这样的限制能避免用户自定义的类冒充核心类库的类,去访问包可见成员。
        6、自定义类加载器
        如上所述,系统类加载器是自定义类加载器的父加载器。若想实现自定义类加载器,需实现java.lang.ClassLoader类。如下示例。
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class MyClassLoader extends ClassLoader{
	private String name;//类加载器的名字
	private String path = "F:\\";//加载类的路径
	private static final String fileType = ".class";//文件的扩展名
	public MyClassLoader(String name){
		super();//显式地调用父类构造器,将该加载器的父加载器设置为默认的系统加载器
		this.name = name;
	}
	public MyClassLoader(ClassLoader parent,String name){
		super(parent);//设置该加载器的父加载器
		this.name = name;
	}
	//将java文件中的数据存储到字节数组中
	private byte[] loadClassData(String name){
		byte[] data = null;//存储字节码
		InputStream ips = null;
		ByteArrayOutputStream baos = null;
		try{
			String cname = name.replace(".", "\\");//获取正确的路径格式
			ips = new FileInputStream(new File(path+cname+fileType));
			baos = new ByteArrayOutputStream();
			int ch = 0;
			while(-1 != (ch = ips.read()) ){
				baos.write(ch);//从文件输入流中读取数据,将读到的数据写到字节数组输出流中
			}
			data = baos.toByteArray();
			ips.close();
			baos.close();//关闭输入输出流
		}catch(Exception ep){
			ep.printStackTrace();
		}
		return data;
	}
	//获取Class对象
	public Class<?> findClass(String name) throws ClassNotFoundException {
		byte[] data = this.loadClassData(name);
		return this.defineClass(name, data, 0, data.length);
	}
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	public String toString(){
		return this.name;
	}
	//测试方法
	public static void test(ClassLoader loader) throws Exception{
		Class<?> c = loader.loadClass("First");
		c.newInstance();
	}
	public static void main(String[] args) throws Exception {
		MyClassLoader loader1 = new MyClassLoader("loader1");
		loader1.setPath("F:\\myapp\\loader1\\");
		MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");
		loader2.setPath("F:\\myapp\\loader2\\");
		test(loader1);
		test(loader2);
	}
}

public class First {
	public First(){
		System.out.println("First的类加载器是:"+this.getClass().getClassLoader());
		new Second();
	}
}

public class Second {
	public Second(){
		System.out.println("Second的类加载器是:"+this.getClass().getClassLoader());
	}
}

        只需要将要加载的类放到类加载器的路径下,即可在命令行完成测试。当然,只需将程序略改一二,就能完成对父委托机制的测试,此处不再讨论。
        7、链接
        随着Class对象的产生,我们已经越来越接近RTTI(运行时类型信息)了。之所以这么说,是因为Class对象构成了RTTI的核心,它能使程序在运行时确定类的确切类型,而这正是强大的多态机制避及的问题。一旦我们获得类的确切类型,就能进行一些特定的操作,而不是基于基类通用的操作,丰富了程序的行为。不仅如此,Class对象还让我们在运行时打开和检查CLASS文件成为可能,从而实现了反射机制。还有诸如注册工厂、动态代理等设计模式的实现。这一切都在酝酿之中~~...
  • 大小: 18.8 KB
3
11
分享到:
评论
5 楼 夜CT 2012-08-12  
4 楼 草帽当家的 2011-09-12  
wenshen22 写道
很好很强大!!


言重了,还差的远呢!
3 楼 草帽当家的 2011-09-12  
cry615 写道
,很不错!

谢谢!
2 楼 cry615 2011-09-12  
,很不错!
1 楼 wenshen22 2011-09-11  
很好很强大!!

相关推荐

    举例讲解Java的RTTI运行时类型识别机制

    原生类加载器主要负责加载Java API类,而自定义类加载器则可以根据应用程序的需求加载特定的类,例如从网络、数据库或其他非标准位置加载。 `Class`对象提供了多种方法来获取类型信息,如`forName()`用于根据类名...

    Java编程思想学习笔记

    在JVM生命周期方面,从启动一个Java程序到程序运行过程中,JVM实例与独立运行的Java程序相对应,具有进程级别的生命周期。 面向对象的知识点涉及UML表示法和设计模式。UML表示法小结中包括类图、顺序图、活动图和...

    深入理解Java的反射机制Java系列2021.pdf

    RTTI在Java中主要通过两种形式存在:一种是传统的类型转换,也就是instanceof关键字和类的cast方法;另一种是反射机制。RTTI的实现依赖于Java类模型中的Class类,它是所有类的最终父类,每个类在运行时都会有一个...

    C++和Java多态的区别

    - **类加载过程**:当Java类被加载到JVM时,类加载器负责构建该类的方法表。 - **动态绑定**:Java中的方法调用分为静态绑定(如静态方法调用)和动态绑定(如实例方法调用)。动态绑定是指在运行时根据对象的实际...

    JAVA反射机制

    每个类都有一个Class对象,类加载器(ClassLoader)在类首次被加载到JVM时创建这个对象。通过Class对象,可以获取关于类的详细信息,比如构造函数、成员变量、方法等。 在Java中,Class类实现了Serializable、...

    Java 基础(7-8) - 反射机制详解.pdf

    每个 Java 类运⾏时都在 JVM ⾥表现为⼀个 Class 对象,可以通过类名.class、类型.getClass()、Class.forName("类名") 等方法获取 Class 对象。 二、Class 类 Class 类是 Java 反射机制的核心。它提供了多种方法来...

    JAVA的反射机制与动态代理.pdf

    - 每个类加载到JVM时,JVM会为该类创建一个`Class`对象。 - 对于所有实例化的对象,它们共享同一个`Class`对象。 - `Class`对象提供了一种访问类内部结构的方式,包括方法、字段、构造器等。 2. **Class对象的...

    java元数据——CLass类

    1. JAVA 使用 Class 对象来执行 RTTI(RunTime Type Information),创建这个类的实例。 2. 验证同一个类的多个对象的Class对象是一个。 获取 Class 对象有多种方式: 1. 通过 Class 的 forName(String name) 方法...

    JAVA程序员面试问题

    连接池预先创建了一组数据库连接,当应用程序请求数据库访问时,直接从池中获取一个已建立的连接,使用完毕后归还到池中,避免了每次访问数据库都要新建和销毁连接的开销。JDBC驱动是Java应用程序与数据库通信的桥梁...

    第6章补充内容第6章补充内容第6章补充内容

    3. **注解(Annotation)**:注解是Java提供的一种元数据,提供了在编译时或运行时向编译器和JVM传递信息的方式。例如,`@Override`注解表示方法是重写父类方法,`@Deprecated`表示方法或类已过时。学习注解可以参考...

    C++与Java的不同.

    对于那些从C++转向Java的开发者来说,了解这两种语言之间的差异至关重要。本文将深入探讨C++与Java的主要区别,并特别关注多态性的不同实现方式。 #### 1. 指针支持 - **C++**: 支持指针操作,这为开发者提供了...

    深入理解Java类型信息(Class对象)与反射机制

    当类被首次使用(例如,通过创建实例或访问静态成员)时,JVM的类加载器会加载对应的Class对象。 Class对象可以通过多种方式获取: 1. 使用`Class.forName(String className)`方法,传入类的全限定名,例如`Class....

    java 多态 经典讲解

    运行时类型识别(RTTI)通过`instanceof`关键字和`getClass()`方法提供了一种检查对象实际类型的方式,从而安全地执行向下类型转换。 #### 八、多态的陷阱:置换私有方法 在多态的场景下,私有方法不参与多态机制,...

Global site tag (gtag.js) - Google Analytics