`
22cgreen
  • 浏览: 53748 次
  • 性别: 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
分享到:
评论

相关推荐

    ArcGIS教程:执行分类

    分类的目的是将研究区域内的每个像元分配给一个已知类(监督分类)或一个聚类(非监督分类)。在这两种情况下,分类的输入是一个包含每个类或聚类的...将位置划分为若干个与聚类对应的自然产生的类的过程也被称为层化。

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

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

    关于Oracle中执行计划稳定性深入研究

    Oracle优化器有两大类,基于规则的和基于代价的。基于规则的查询,数据库根据表和索引等定义信息,按照一定的规则来产生执行计划;基于代价的 查询,数据库根据搜集的表和索引的数据的统计信息综合来决定选取一个...

    大学生兼职服务类APP的调查与研究.pdf

    "大学生兼职服务类APP的调查与研究" 本文主要研究了大学生兼职服务类APP的现状和问题,并对其进行了深入的分析和研究。该研究报告分为五个部分,分别是:兼职服务类APP概述、兼职服务类APP的基本情况、兼职服务类...

    交通运输类物流行业执行供应链服务领域分析报告(研究报告).pdf

    交通运输类物流行业执行供应链服务领域分析报告(研究报告).pdf

    论文研究-基于多agent的离散制造业制造执行系统框架研究.pdf

    构造了对应的agent模块,以此提出一种基于多agent的分布式离散制造业制造执行系统体系结构,并研究了其中每个agent的运作机制与多agent之间的交互协调机制。特别是构造了策略agent,它与调度agent协同,可更好地实现...

    论文研究 - 成年特发性癫痫患者的执行功能评估

    目的:认知障碍是癫痫患者中常见的主诉,其发生在疾病过程中是一个重要话题,因此我们的研究旨在检查成年特发性癫痫患者的执行功能。 方法:连续40例年龄在18-45岁,智商&gt; 85的特发性癫痫(全身性或局灶性)成年患者...

    ACP理论的平行执行方式分类研究

    针对人工系统、计算实验和平行执行理论(Artificial systems,computational experiments,parallel execution,ACP)中的平行执行方式,论文给出了不同分类方法,特别是对整体平行执行、局部平行执行和混合平行执行分类...

    论文研究-PostgreSQL查询优化中的等价类研究与改进.pdf

    研究了PostgreSQL查询引擎中等价类在查询优化过程中的应用原理,详细阐述了其如何帮助优化器产生潜在的等值连接,等式约束和记录排序信息。同时也发现PostgreSQL查询引擎并没有充分利用等价类的属性约简特性,以及...

    论文研究-网络视频流量分类的特征选择方法研究.pdf

    准确,高效的业务流识别与分类是保障多媒体通信端到端QoS(Quality of Service),执行相关网络操作的前提。如今数据规模的剧烈增加为业务流的分类提出了挑战,而特征选择能够尽可能地减少特征维数,去除冗余特征,...

    金融资产重分类研究

    关于如何更好地执行金融资产标准,本文采用比较分析,文献收集等方法。 结合实际工作进行系统研究; 分析了修订的背景,重新分类的内容及其影响。 通过研究可以得出结论,金融资产的重分类可以减少会计主体的使用,...

    6提升执行力(欧阳红).pptx

    五是“执行讲时效”的理念,对每一项重点工作都提交局务会研究讨论,确定具体的牵头科室和负责人,明确时限要求和阶段性工作目标。 五、如何挑选有执行力的人 挑选有执行力的人需要从七个方面入手:一是自动、自发...

    人形机器人感知硬件专题研究:人形机器人的五类感官和硬件支撑.docx

    "人形机器人感知硬件专题研究:人形机器人的五类感官和硬件支撑" 人形机器人感知硬件专题研究是当前机器人行业的热点话题,人形机器人的五类感官和硬件支撑是其核心组成部分。本文将对人形机器人的五类感官和硬件...

    论文研究-一种基于PCA的组合特征提取文本分类方法.pdf

    为了获得更好的文本分类准确率和更快的执行效率, 研究了多种Web文本的特征提取方法, 通过对互信息(MI)、文档频率(DF)、信息增益(IG)和χ2统计(CHI)算法的研究, 利用其各自的优势互补, 提出一种基于主成分分析(PCA)...

    论文研究 - 增强战略执行力的模型

    战略管理研究始终侧重于战略决策的效果,而对战略执行的研究却很少。 本文的重点是实现战略目标(战略执行)的能力,它有三个结论。 首先,它重新定义了战略执行是实现战略的能力; 其次,影响战略执行的因素可以...

    论文研究-无线传感器与执行器网络中协同通信研究综述.pdf

    首先介绍了WSANs协同通信的意义和作用;然后根据协同级别对协同通信进行分类,分别讨论了每一类中重要和有代表性的协议,并从主要的网络性能方面进行对比分析;最后提出了几个WSANs协同通信中需要进一步研究的问题。

    赣州顶级商务会所研究执行案.pptx

    赣州顶级商务会所研究执行案.pptx

    论文研究-基于HBase的多分类逻辑回归算法研究.pdf

    为解决在大数据环境下,用于训练多分类逻辑回归模型的数据集可能会超过执行计算的客户端内存的问题,提出了块批量梯度下降算法,用于计算回归模型的系数。将训练数据集存入HBase后,通过设置表扫描对象的起始行键...

Global site tag (gtag.js) - Google Analytics