`
22cgreen
  • 浏览: 55188 次
  • 性别: Icon_minigender_2
  • 来自: 广州
社区版块
存档分类
最新评论

类是怎样被执行的研究

阅读更多
1)类是以编译后的字节码.class类型存于硬盘或其它存储介质上.我们打开被编译的文件也能看出一些
东东,上面的部分看不懂,但从能看得懂的来分析有几下几点
1、class文件中,把(.)点号转成了(/),也就是真实的路径。我们在类中定义private Pstring good;
在class中变为: good dlp/oa/pub/Pstring 很显然java文件在编译后,会把各此的属性配置全路径,
也就是虽然我们在程序中用Pstring good,然后import dlp.oa.pub.Pstring 但实际上编译成class后
会变成 good dlp/oa/pub/Pstring
2、文件存在自身的路径,还有继承类的路径
3、有LineNumberTable LocalVariableTable this /dlp/oa/test/Three
4、有源码名称。

2)类文件.class文件是怎样进入内存的。
我们知道JVM有几个类加载器,事实上所有的类文件都是通过加载器进行加载的,JVM中有默认的几个类加载器
1、加载核心类的加载器,2、加载ext目录的加载器,3、加载claspath目录的加载器。
以tomcat为例,看tomcat是怎样启动的。tomcat中有一个startup.bat 批处理文件,这个文件会启动另一个批处理文件
catalina.bat 而这个批处理会设置set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\bootstrap.jar
也就是把bootstrap.jar所在目录加入classpath中,这样就可以通过jre来运行bootstrap.jar,我们看到在这个包中的
MANIFEST.MF的文件内容如下:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: 1.5.0_06-b05 (Sun Microsystems Inc.)
Main-Class: org.apache.catalina.startup.Bootstrap
Specification-Title: Catalina
Specification-Version: 6.0
Class-Path: commons-daemon.jar commons-logging-api.jar tomcat-juli.jar
  tomcat-coyote.jar
  这里Main-Class: org.apache.catalina.startup.Bootstrap 指定了主函数所在的类,
  tomcat在最后的批处理中执行了一个命令如下:
  start "Tomcat" "C:\Java\jdk1.5.0_16\bin\java"  -Djava.util.logging.manager=org.a
pache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="D:\apache-tomc
at-6.0.14\conf\logging.properties"   -Djava.endorsed.dirs="D:\apache-tomcat-6.0.
14\endorsed" -classpath "C:\Java\jdk1.5.0_16\lib\tools.jar;D:\apache-tomcat-6.0.
14\bin\bootstrap.jar" -Dcatalina.base="D:\apache-tomcat-6.0.14" -Dcatalina.home=
"D:\apache-tomcat-6.0.14" -Djava.io.tmpdir="D:\apache-tomcat-6.0.14\temp" org.ap
ache.catalina.startup.Bootstrap  start
从中可以看出就是通过设置classpath,然后用java org.apache.catalina.startup.Bootstrap
设置classpath是为了找到包D:\apache-tomcat-6.0.14\bin\bootstrap.jar 及主方法类:java org.apache.catalina.startup.Bootstrap
如此可知tomcat的启动主函数类,是通过java.exe运行的,也就是通过java的类加载器加载的。
其实可以发现其实main方法也是java的一种约定,就像接口定义一样,以便于加载他的程式能知道从那里进入进行操作。
我们可以认为java.exe 执行一个类或jar是这样的,他先用类加载器进行加载,并得到class类型的引用,因为main方法是类方法
不用实例化,因此他就用反射机制取main方法,如果存在就进入执行,这也是java运行其它程式的一种约定,而tomcat实际上也就有一个
类加载器来加载新的类来运行,类加载器知道加载什么类,但并不知道应运行什么方法,我们自己开发的程式可能知道,如:
A a = new A();
a.show();
很自然加载类A,然后实例化,最后从show()方法进入执行。但是对于tomcat运行servlet时,他并不知道从那个方法进入,如果系统和用户编程时
没有事先约定,tomcat加载servlet类后,他从什么地方去执行呢?因此我们常用必须继际某些接口或类,或实现虚方法的情况,这些从系统画出
的框框要编程者去准遵守。

因此在servlet中我们必须继承一些类,然后要实现get或post方法之类。这些就是tomcat知道从约定的方法进入执行。

3)类是怎样被加载器加载进系统的。
我们还以tomcat为例,tomcat也有多个类加载器,他们中有些是加载tomcat的一些类库和包,位于tomcat的lib目录下,但我们关心的是
web类(也就自己开发的J2EE)应于的类加载器,这个类加载器加载的目录指向相应项目的class目录,如:
D:\apache-tomcat-6.0.14\webapps\dlp_oa\WEB-INF\classes
我们自定义类加载器时主要是实现findClass方法,
public Class findClass(String name){
  byte[] data=loadClassData(name);
  return defineClass(name,data,0,data.length);
}
很显然每个类加载器都有这么一个方法,其目的就是找到指定的class文件并读取然后转成byte[]字节流,最后用defineClass方法把字节流
转换成class的实例。

defineClass方法属性本地方法,非java写成,class是字节码,很显然,JVM是按字节解释执行。
在测试中我现,我自己开发的一个类加载器,他的类查找顺序,也是委托的方式,从最顶层类加载哭进行加载,
在测试中我把类放在java中的ext目眼中显示如下:
D:\java>C:\Java\jdk1.5.0_16\bin\java FileClassLoader
One
sun.misc.Launcher$ExtClassLoader
显示发现加载器并非自定义的加载器,而是上层的加载器 ExtClassLoader,在自定义的类加载器中如果不指定父加载器,默认情况是系统类加载
器,也就是appClassLoader.

4)类加载后是怎样区分的。
类加载器被加载后,有一个列表来记录类的唯一标示,也就是类的全名(包含包名+类加载器实例)来标示这个类的类型。

5)类加载器要注意的几点。
  1、类加载器的父加载器,不是指继承父类的实例,也不是加载自己身的加载器,而是在编程时设定的。其实一般继承ClassLoader的加载器
  的父加载器为AppClassLoader
  2、系统中的ExtClassLoader与AppClassLoader都是Launcher的内部类,位于:sun.misc 包下,并都继承java.net.URLClassLoader,类
  java.net.URLClassLoader类继承java.security.SecureClassLoader,而java.security.SecureClassLoader又继承ClassLoader
  从源码分所知AppClassLoader,把this.val$extcl,一直使用super来执行父类构造方法,最后在类,ClassLoader,把值传给了this.parent
  protected ClassLoader(ClassLoader paramClassLoader)
  {
    SecurityManager localSecurityManager = System.getSecurityManager();
    if (localSecurityManager != null)
      localSecurityManager.checkCreateClassLoader();
    this.parent = paramClassLoader;
    this.initialized = true;
  }
  其实parent也是一个ClassLoader类型,
  3、我在继承ClassLoader时,执行父类的带参构造方法就能把自定义类加载器的父加载器进行设定。
 
6)类是怎样被执行的。
java的类当然是JVM虚拟机去执行,类被加载器加载时,以文件读取的方式进入内存,当然java读取文件,也是依赖于本地操作系统的API进行
读取的,读取文件后转换成byte[],也就字节数组,最后JVM读取并解释这些字节码,并转换成相应本地系统的API调用,而完成执行的过程。
从而可知可以用勾子程序拦截java的API调用。当然jvm中维护着一个表,类及类加载器的列表,那是JVM的规则,JVM使用这套字节码规则来
转换成api调用和得到相应参数和数据结果等。

7)类加载器为什么不会重复加载类?
其它在ClassLoader中的loadClass方法中有一段代码是用于检测此类是否已加载,
Class localClass = findLoadedClass(paramString);
最后调用了。
private final native Class findLoadedClass0(String paramString);
不过此方法是一个本地方法,并非java实现。
如此看来,如果自定义类加载器不重写loadClass方法,是很难重新加载一个新版本的同样路径和名称的类的。

8)类的加载方式。
类的加载有下面的2种方式:
1、Class c1 = Class.forName ("java.lang.String");

2、Class a = Oa120.class;
Two.class.getClassLoader().loadClass("One");

9)怎样重新加载新版本类
package com.chen.test;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;


public class Fcl extends ClassLoader {
public static final String drive="D:\\temp\\";
public static final String fileType=".class";

public Class findClass(String name){
  byte[] data=loadClassData(name);
  return defineClass(name,data,0,data.length);
}

private byte[] loadClassData(String name) {
  FileInputStream fis=null;
  byte[] data = null;
  try {
   fis = new FileInputStream(new File(drive+name+fileType));
   ByteArrayOutputStream baos=new ByteArrayOutputStream();
   int ch=0;
   while((ch=fis.read())!=-1){
    baos.write(ch);
   }
   data=baos.toByteArray();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return data;
}

@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class localClass = null;
try
    {
      if (this.getParent()!= null)
        localClass = this.getParent().loadClass(name);
      else
        localClass = findBootstrapClass(name);
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      localClass = findClass(name);
    }
    return localClass;
}

private native Class findBootstrapClass(String paramString)
throws ClassNotFoundException;

}

注:主要是重写loadClass方法,不要其执行Class localClass = findLoadedClass(paramString);这行代码。在测试中发现
在加载类时,系统会每次都会去加载class文件。

10)类加载器测试(1)
------------------------------------------------------
在测试过程中,我发现重启后tomcat后,类加载器的地址是一样的,如:
vvvvvvvvv
com.chen.test.Fcl@13f136e
dddddddddddddddddddd
WebappClassLoader
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@12b3374
每次都是13f136e和12b3374,是不是程序在编辑时已确定了这个地址呢?有待研究。
如果重新请求,因为com.chen.test.Fcl这个加载器是用new的方法产生了一新的,因此后地址发生了变化,如:
vvvvvvvvv
com.chen.test.Fcl@14d5bc9
dddddddddddddddddddd
WebappClassLoader
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@12b3374

如此可看出StandardClassLoader还是同一个。我把自定义的类加载器改成了static,并只实例化一次,结果发现
第一次的com.chen.test.Fcl@18f7386 地址发生了变化,不过这些定义为static的后,多次调用地址没有发生变化
也就说明只有一个实例,同时测试时发现这次没有去加载新版本的Class了,而是用系统已存在class模板。

vvvvvvvvv
com.chen.test.Fcl@18f7386
dddddddddddddddddddd
WebappClassLoader
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@12b3374

  类加载器测试(2)
  我把loadClass重写,同时不管有没有加载过,一样执行findClass,这时发现第一次加载时没问题,第二次加载时出错,
  说“不能重复加载一个同样的类”,别外在测试时发现当代码修改过后Fcl@18f7386后面地址会发生变化
  测试发现如果我们不用
  if(fl==null)
{
fl = new Fcl();
}
而是每次都实例化的话,加载器的地址也会发生变化。
 
11)tomcat的在项目发布时,类加载器没有发生变化,他是怎样重新加类的呢?
---------------------------------------------------------------------------------------
我自已写的类加载器,在重写loadClass方法时发现当加载器相同的情况下,无法加载同样的类,但tomcat是怎样办到的呢?
很显然他要去掉内存中存在模板。
0
0
分享到:
评论

相关推荐

    Java虚拟机解释执行机制研究.pdf

    当类准备好后,就会被初始化,即执行静态代码块和静态字段的初始化。 解释执行是JVM执行Java字节码的一种方法,它不需要将字节码转换成机器码,而是直接由解释器逐条解释执行。这种方式简单快捷,但执行效率相对较...

    调节阀执行机构的工作原理与分类研究.doc

    调节阀执行机构的工作原理与分类研究.doc

    Java虚拟机解释执行机制研究.zip

    不同于传统的编译型语言,Java代码首先被编译成中间表示——字节码,然后由JVM的解释器逐条解释执行。这种机制使得Java具有跨平台的能力,因为字节码不依赖于特定的硬件架构。不过,解释执行的效率相对较低,为了...

    虚拟机CPU平台的基本执行环境研究.pdf

    虚拟机CPU平台的基本执行环境研究 虚拟机是指通过软件方式模拟出具有完整计算机硬件系统功能的并运行在一个相对完全隔离环境中的完整计算机系统。虚拟机就像一台真正的计算机,它一样拥有自己的CPU、寄存器组、指令...

    食品机器人末端执行器研究现状与展望.pdf

    根据食品加工和包装的需要,食品机器人被分为两大类:食品加工机械和食品包装机械。食品加工机械包括粮油加工设备、果蔬保鲜与加工设备、畜禽产品加工设备、水产品加工设备、方便食品加工设备、饮料加工设备和食品...

    我国艺术类高校毕业研究生就业工作对策研究

    【我国艺术类高校毕业研究生就业工作对策研究】 随着我国高等教育的普及与发展,艺术类高校毕业研究生的就业问题日益凸显。研究生就业不仅关乎个人发展,更影响到家庭与社会的稳定。艺术类研究生作为高层次的艺术...

    武汉市M区城市垃圾分类政策执行过程中的问题及对策研究.docx

    武汉市M区城市垃圾分类政策执行过程中的问题及对策研究.docx

    Python伪装文件类对象输入输出重定向方法研究.pdf

    在讨论Python伪装文件类对象输入输出重定向方法研究之前,我们首先需要了解什么是输入输出重定向,以及它在Python程序评测中的作用和重要性。 输入输出重定向是操作系统级别的一个功能,它允许将程序的标准输入...

    经管类学术型研究生科研能力研究

    经管类学术型研究生科研能力研究的核心在于分析与提升研究生在经济管理领域的科研能力。科研能力包括提出、分析和解决经济问题的能力,不仅涉及学术论文写作,还包括科研项目的申报与执行,以及学术交流等方面。构建...

    高中学生研究性学习研究报告《垃圾分类的研究与调查》.pdf

    《垃圾分类的研究与调查》这份研究报告主要探讨了垃圾分类的重要性和实施情况,特别关注了我国与国外,尤其是日本的垃圾分类实践。垃圾分类对于环境保护、资源回收以及社会经济具有显著意义。 首先,垃圾分类的意义...

    WordPress 5.0.0远程代码执行漏洞研究.pdf

    《WordPress 5.0.0 远程代码执行漏洞研究》这...总之,这篇研究论文深入剖析了WordPress 5.0.0的远程代码执行漏洞,为安全从业者提供了新的视角和思路,有助于企业和个人更好地应对这类威胁,提升网络空间的安全水平。

    可执行UML 建模技术研究1

    【可执行UML建模技术研究】 UML(统一建模语言)是模型驱动架构(MDA)的核心技术,主要用于软件开发的分析和设计阶段。然而,标准的UML存在语义模糊、不可执行和无法直接展示数据处理过程等问题。为解决这些问题,...

    网络计算系统的分类研究

    这种分类方法考虑了网络计算系统的执行方式、控制机制以及系统层次结构,能够更全面地反映网络计算系统的特性,为网络计算系统的深入研究和应用提供了新的视角和工具。 #### 执行维度 执行维度主要关注计算任务...

    芯片上的类细胞系统可执行基因表达功能.pdf

    根据提供的文件内容,本文将详细解析“芯片上的类细胞系统可执行基因表达功能”这一主题所蕴含的知识点。 ### 芯片上的类细胞系统 芯片上的类细胞系统是指一种模仿真实细胞内部功能的微观装置,它能够在芯片上模拟...

    深入研究Java的类加载机制.pdf

    深入研究Java的类加载机制 Java类加载机制是Java虚拟机的一项核心技术,可以在运行时刻动态地加载或替换系统的某些功能模块,而不影响系统其他功能模块的正常运行。类加载机制是Java虚拟机中的一项重要技术,可以使...

Global site tag (gtag.js) - Google Analytics