Java中的可变性分析的制作方法

文档序号:6472666阅读:192来源:国知局

专利名称::Java中的可变性分析的制作方法
技术领域
:本发明涉及用于计算机程序的面向对象的编程语言领域,尤其是,涉及检测在任意程序组件中的字段和类(class)的可变性(mutability)。
背景技术
:在1995年末被引入时,编程语言Java给因特网带来一场风暴。这一点的主要原因为Java是一种解释性编程语言,这基本上意味着它使用和诸如C或C++编程语言不同的编译/执行范例。以诸如C或C++这样的高级编程语言书写的程序可以由人来读、写、和理解,这些程序需要被翻译成可由实际运行该程序的计算机理解的机器码。这就是编译程序所做的事情。另外,编译程序在翻译代码时同时优化它。编译的最终产品是机器码,从定义上可知是与机器相关的,意味着该代码是特定针对运行它的那种类型计算机的,而不能由不同类型的计算机所理解。这一点的一个简单的例子是为苹果机编译的程序不能在国际商业机器(IBM)兼容PC机上运行。这一点称为“与平台相关”。另一方面,诸如Java这样的解释性编程语言不为特定类型的计算机编译(Java是SunMicrosystems公司的商标)。它们是平台独立的。这一点是通过在编译的程序和特定平台之间放一个中间的Java虚拟机(JVM)实现的。换句话说,当编译一个Java程序时,最终结果不是机器码,而是可由JVM理解的字节码。JVM是与机器相关的,它作为安装到特定机器中JVM的字节码的解释程序。只要该机器安装有JVM就允许Java程序编译和移植到任何机器中。正是这种平台独立性使Java特别适合于因特网。一个计算机一旦安装有JVM,则不管该计算机是苹果机、WintelPC、Sun、Digital等,通过因特网下载的Java编译字节码程序就能在其上运行。虽然Java通常作为解释性编程语言运行,但是应该注意,它可以静态地或在运行时被优化和编译(亦即适时编译程序)。Java是一种面向对象的编程(OOP)语言。这意味着其焦点是对象,而不是过程(如在C或BASIC中那样)。粗略说,对象包括数据和操作该数据的方法。Java中的编程可以理解为书写不同对象的说明。更特别地说,在OOP中,“类”定义为一种实现特定类型对象的数据和方法集合。类定义“实例(instance)变量”和“类变量”,同时说明类实现的接口和该类的直接“上类(superclass)”。广义讲,类可以理解为总的定义,而对象是一个类的一个“实例”。例如,命名为圆的类可以用半径和原点的位置的变量来定义。一个特定的圆c可以通过用半径和原点位置的特定值调用圆类而具体实现。因为半径和原点位置对圆类的该实例是特定的,因此它们是“实例变量”。与此对照的是,“类变量”是与类整体相关的数据项。例如,值pi=3.14可以是圆类中的类变量。另一个例子是在圆类中定义的变量num_circles,它在每具体实现一个圆时增加1。这些类变量与整个类相关,而不是与一个实例相关,且用静态修正符说明。Java中的类形成一个类层次结构,在这里,一个类可以是对另一个类的“上类”或“下类”。例如,形状可以是圆的上类,而提供操作和画圆类的具体实现的对象的能力的图圆(GraphicCiecle)可以是圆的下类。下类继承它的上类的行为。在Java中,“包(package)”是类的扩大的集合,Java有程序员执行一般任务而用的缺省包。例如,Java.io包具有处理输入和输出的类,Java.net包具有支持网络功能的类,和Java.awt包提供建立图形用户接口组件的类。继续说明Java某些独特的特征,应该注意,Java是一种动态语言。这意味着任何Java类可以在任何时间加载到一个运行的Java解释程序中。然后,这些动态加载的类可以动态具体实现。Java还是一种用于联网的嵌入式语言。使用Java.net包,很容易通过网络访问文件或资源,就像它们是位于本地的文件或资源。因为Java对于联网既是动态的,又是嵌入式的,因此对于Java解释程序来说能够从因特网下载和运行代码。这当万维网流览器下载和运行Java小程序(Java小程序是由已经运行的Java应用程序加载和运行的类)时就是这样。当前,因特网Java小程序是Java的到处存在的应用,但是Java具有能力建立动态使用网络分布式资源的任何类型的程序。因为在可以下载活动代码的系统中所涉及的固有安全风险,Java具有几条恶意代码的防线。首先,不像C或C++,Java没有可以用来访问一个字串或数组边界外存储器的指针。与没有指针相关联,Java禁止对存储器的任何直接访问,从而阻止任何来自那个方向的安全性攻击。第二,Java解释程序对它加载的任何不信任的代码的字节码验证,这将防止来自利用Java解释程序中执行弱点的恶意代码。第三,Java使用一个安全“沙箱(sandbox)模型”,在这里,不可信代码被放在一个“沙箱”中,在这里可以安全地播放,而不对完全的Java环境做任何损害。当一个小程序在沙箱中运行时,对它可以做的事情有很多安全限制。这意味着阻止恶意代码干扰在同一Java环境中运行的其它应用程序,或获得对在底层操作系统或网络中的资源的未授权访问。通过对Java代码挂接数字签名而提供第四层安全。这些数字签名可以以密码安全和不可伪造的方式建立源代码。用户指定一个特定的源代码是否可信,并且,如果从一个可信源得到代码,则接受它并运行。Java的另一特征是其存储器分配和释放的方法。在C或C++中,程序员分配存储器和然后以审慎的方式释放存储器。换句话说,C++程序员在一个对象或方法的开始明确分配存储器来保存数组、变量等,然后当它们不再被使用时明确释放该存储器。与此相反,Java程序员既不分配也不释放存储器。取而代之的是Java使用垃圾收集,它操作如下Java解释程序知道它曾经分配过那些对象。此外,它还知道哪个变量引用哪个对象,和哪个对象引用哪一个另外的对象。因为这一点,它可以知道一个被分配的对象何时不再由任何其它对象或变量引用。当找到这种对象时,它可以被“垃圾收集”安全地破坏。最后,Java使用可在展开时配置的组件、应用程序级的软件单元。当前,有四种组件企业Bean,万维网组件,小程序,和应用程序客户。企业Bean实现商业任务或商业实体。万维网组件,诸如服务小程序,响应请求提供服务。如前面提到的小程序通常在万维网浏览器中执行,但是可以在支持小程序编程模型的其它各种应用程序或设备中执行。应用程序客户是第一层客户程序,它在它自己的Java虚拟机中执行。通过容器给组件提供生命周期管理、安全、展开、和运行时间服务。每一类型容器(企业JavaBean(EJB),万维网,Java服务器页(JSP),服务小程序,小程序,和应用程序客户)还提供各组件专门的服务。从上面对Java的说明已经清楚,Java的一个基本属性是模型中的知识的本地化,它称为“封装(encapsulation)”。因为对象封装数据和实现,因此,一个对象的用户可以视该对象为一个提供服务的黑盒子。可以增加、删除、或改变实例变量和方法,但是只要由该对象提供的服务保持不变,则使用该对象的代码可以继续使用它,无需重写。然而,当一个对象或组件依赖于一个共享变量或对象的状态和另一个组件或对象改变该变量或对象的状态时就会出现问题。在这种情况中,换句话说,共享对象不被封装。这有时被称为分离错误(isolationfault)。为Java中的共享状态的机制是通过类变量实现的,亦即使用静态修改符说明的字段。类变量是通过它的类名访问的,而不是通过对象引用。这样,变量被认为是由所有可以访问说明类的代码共享的。因为Java组件(小程序,服务小程序,JavaBean和企业JavaBean)市场的迅速发展和Java对开发中间件的使用,这些分离错误具有特别的重要性,所述中间件的例子有由万维网浏览器使用来运行小程序的AppletViewer,在服务器上运行服务小程序的JavaServerToolkit(Java服务器工具包)(JST),和运行EJB的Containers。这些中间件系统的引用实现基于在Java运行时间系统的一个单实例中并发执行多个组件。Java运行时间系统是,在其中可以运行为JvM编译的程序这样的软件环境。该运行时间系统包括为加载以Java编程语言写的程序、动态链接本地方法、存储器管理、例外处理和实现可以是Java解释程序的JVM所必需的所有代码。在多个并发或串行执行的程序之间的分离错误可以导致大量问题产生,特别是在下列领域完整性-在全局字段/对象中保存的一些状态信息可以由在JVM中运行的任何程序修改。一个这样的例子是缺省场所(国家,语言,变体)。如果两个或者多个程序依赖于这一全局状态信息,和它们两者都试图改变缺省值,则它们的执行结果可能不可预测。安全性-改变状态的能力或观察状态改变导致安全性暴露。在一些场合,属于类的全局字段可以在运行时间拥有对那些对象的引用,这些对象是定义首选(overriding)方法的下类的实例。这些方法可以执行应用程序开发者未打算的操作,和可以产生恶意行为(例如使用用户ID/口令提示打开一个GUI窗口)。另外,恶意代码可以以不可预测的方式改变Java运行时间的状态。在Java开发工具包(JDK)版本1.1.1中出现的一个实际的实现问题是由于对象的共享。其结果是一个无特权的小程序能够模仿一个可信签名,引起严重的安全问题。遵从组件模型-应用程序代码可以运行进入可缩放性问题。应用程序代码常常使用全局变量来共享该类实例之间的状态信息。问题是在一些应用程序模型中,可以在退回到附属存储器的一个容器中产生EJB的一个实例,然后在一个不同的容器中重新激活。当重新激活时,类变量/实例变量的状态信息存储在一个不同的容器中。最终结果是可以有存储器尖峰-信息被产生并存储在变量中,但是永远不释放-而EJB不再是位置透明的。因此,需要识别可变性变量,这些变量可以由多于一个的组件改变,以便识别和停止分离错误。
发明内容根据本发明,提供一种检测面向对象编程语言组件中类的可变性的系统和方法。在该种系统和方法中,获取一组类,所述类的每一个被分为可变的、不可变的、和未决定的其中之一,然后测试每一未决定的类。未决定的类的测试包括测试未决定类中的非静态字段,如果在所述未决定的类中的任何非静态字段是可变的,重新分类所述未决定的类为可变的;如果在所述未决定的类中的所有非静态字段是不可变的,和重新分类所述未决定的类为不可变的。测试未决定类中的每一字段包括决定在所述每一字段中的每一变量和每一对象的可能状态修改,所述状态修改在分析范围内由本发明的方法进行;决定在所述每一字段中的每一变量和每一对象的封装的可能破坏,所述封装的破坏由在分析范围内的方法进行;如果未发现可能的状态修改或封装的破坏的话,分类所述每一字段为不可变的;如果发现可能的状态修改或封装的破坏的话,分类所述每一字段为可变的;如果类可变性信息不充分的话,分类所述每一字段为未决定的。重复测试每一未决定的类的步骤,直到未决定类的数目在重复所述测试步骤后等同于在重复所述测试步骤前的未决定类的数目;然后把剩余的未决定类重新分类为可变类。根据本发明,提供一种用于测试在一种面向对象的编程语言组件中的变量、对象、字段、和类的系统和设备。所述系统和设备包括具有三层的可变性分析器第一层具有至少一个内核库和至少一个数据流分析引擎,用于提供程序组件的一个特定的抽取;第二层具有至少一个实用工具模块,用于使用所述至少一个数据分析引擎的结果来产生基本结果;第三层具有至少一个可变性子分析模块,用于产生最后结果。附图简述现在仅以举例方式,参考附图来说明本发明,附图中图1是根据本发明的优选实施例的可变性分析器的方框图;图2是可变和不可变静态字段的分布图,比较基于访问的算法结果和为根据本实施例的可变性分析器的结果;图3是为根据本发明的优选实施例的可变性分析器所分析的rt.jar的不同部分的分析时间和被分析库大小的图;图4是为根据本发明的优选实施例的可变性分析的子分析的流程图。发明详述本发明的优选实施例的意图提供一种检测在任意Java组件中的字段和类的可变性的设备和方法。具体说,说明了一种可以列出所有不可变类和字段且标识可以进行改变的地方的位置的静态分析。在本发明的优选实施例中,如果它的值或任何从它可到达的变量的值在其初始化点后可以被修改的话,一个变量被认为是可变的。特别是,该算法注目于开放世界分析范围(或组件分析),在这里,所有要被执行的代码在分析时间不必一定可用。该优选实施例处于Java环境,但是它也可以应用于其它面向对象的编程(OOP)语言。本发明的优选实施例使用一组算法,它结合用于Java组件的可变性分析的数据流技术。焦点是在软件组件(例如库或Bean)的分析上,而不是在整个程序上。这通过链接可变性的概念与封装和辖域(scoping)的概念实现。在优选实施例中,当一个组件依赖于一个共享的变量或对象的状态和另一个组件改变该状态,将其组成组件到一起时产生分离错误。在本发明的优选实施例中,使用一个可变性分析器来执行对一个Java组件的一个开放世界范围的静态分析以便验证该组算法。可变性分析器为该组件中的每一静态字段和每一类分为可变的或不可变的。虽然根据本发明的优选实施例的可变性分析器是非常保守的,但是其它实施例可以不那么保守。本申请的剩余部分组织如下。第一部分提供在可变性分析中使用的定义。第二部分介绍静态分析以决定组件编程领域中的可变性。算法通过一组子分析说明。第四部分说明可变性分析器分析工具和表示实验结果。第五部分提供结论和介绍如何进一步增强这一工具的思想。I.定义在这一部分,引入Java程序中的状态的定义,在这里,变量可以保存基值(例如字符值或整数值),或对对象的引用。接着,介绍对地址可变性的正式定义。在本发明的优选实施例中,假设和使用Java语言的类型安全和访问修改符。如同下面要讨论的,分析对分类文件进行,并将使用分类文件拓朴。A.变量状态和对象状态Java中的对象要么是类实例,要么是数组。对象的具体实现涉及分别建立一组实例变量或数组组件。因此,对象表示相关变量的集合。Java中的类变量相应于在类说明内使用静态修改符说明的字段。注意,在接口说明中说明的字段必须被定义为静态的。相反,实例变量相应于在类说明中不用静态修改符说明的一个字段。类实例是相应于在这一类和在它的所有前辈中说明的非静态字段的变量的集合。如果它的实例包括与该字段关联的一个变量的话,类类型实现非静态字段。对于基元类型,变量的状态由它所保存的基元值定义。然而,持有对一个对象的引用的变量更为复杂,因为它可以间接引用其它变量。换句话说,引用类型变量的状态递归依赖该被引用对象的状态。正式区别下面的概念一个变量的值状态是在该变量中保持的值。一个变量的状态由它所达到的变量的所有值状态集合定义。对象的状态由它所有关联变量的状态定义。显然,基元变量的状态与它的值状态一致。值状态为非零的引用类型变量状态由该变量的值状态连同被引用对象的状态一起递归定义。B.不可变性定义为定义一个变量或对象的不可变性,必须引用一个被认为是当被“完全建立”时的特定执行点。引用该点作为该变量或者该对象的初始化点,并定义如下一个类变量的初始化点是在完成它的相应<clinit>方法时。一个实例变量或一个类实例的初始化点是在完成它的相应的<init>方法时。一个数组实例或者它的分量的初始化点是在执行一个相应的数组建立指令(亦即newarray,anewarray,或multianewarray)时。已经定义了初始化点后,可以作出不可变性定义当且仅当变量或对象的状态在相应初始化点后永远不改变时,该变量或该对象是不可变的。当且仅当相应于一个字段的所有变量是不可变的时,则该字段是不可变的。当且仅当由一个类实现的所有非静态字段是不可变的时,则该类是不可变的。注意,因为抽象类和接口不能被初始化,因此这里不考虑它们的可变性。为本优选实施例的目的,一个对象的状态连同明确相应于非静态字段的变量一起被决定。然而,JVM可以隐含连接与该对象的其它存储器位置。一个这种隐含的变量,或“隐藏”字段,是与每一Java对象关联的锁。然而,该定义意味着,如果一个对象没有实例变量,则它是不可变的。于是,因为java.lang.Object没有说明的非静态字段,因此它被定义为不可变类。C.访问修改符和访问控制Java通过访问修改符提供用于控制对对象的访问的基本手段专用修改符、公共修改符和保护修改符。这些修改符限制类和字段的可见性。另一个访问修改符是最后修改符。这一修改符为防止变量的不希望的可变性提供部分支持。JVM禁止对相应于一个最后字段的变量的指定。这样,一旦JVM初始化字段,则不能改变它们的值状态。然而,如果这种变量保持有对一个类实例的引用,则被引用的对象的状态可以通过对该对象的操作而改变,虽然该变量将始终引用同一对象。这一点同样适用于数组。虽然相应于一个引用该数组实例的最后字段的变量的值状态将保持为不可变可以改变一个数组的分量。注意,由于影响类和方法之间的继承和覆盖(overriding)关系对方法和类的最后修改符具有完全不同的解释。一个说明为最后的类可以不是下类。对于可变性分析的一个结果是,每当一个最后类是一个变量的说明的类型,则它也是它的运行时间类型。这样,一个最后的基元字段总是不可变的;所以它是一个最后引用类型字段,它的说明类型是最后不可变类。在访问修改符之外,可以通过由Java运行时间提供的各种安全和层次结构类加载机制强制执行更广的辖域和访问限制,例如由安全管理器强制执行对某些包增加新类的限制。由Java运行时间安全系统提供的辖域限制的讨论超出了本申请的范围。C++包含一个友指定符,它允许交叉包成员访问。与C++相反,Java利用Java运行时间安全系统来限制对方法和被保护的Java资源的访问。Java通过嵌套的类和接口的概念提供(在资源级)类之间的某些“友”关系,这包括称为内部类的非静态类。这些类是它们封装类型的合约或实现的一部分,因此具有和其他成员同样的访问能力选择。然而,在JVM级,不存在这样的嵌套关系。在实践中,编译程序产生合成字段和合成存取器方法来支持在嵌套和封装类的成员之间的访问。在该资源级上似乎是更严格的访问性规则实际上是在对象代码级上较弱的保护。然而,通过访问修改符的保护是有限的。Java代码可以使用本地方法(非Java代码)和反射(在Java.lang.reflect中的类/方法)来访问类成员,无需依赖Java访问修改符。通常使用安全机构来限制违反Java访问规则的访问。这里的分析不处理本地代码,也不考虑来自反射的动态效果。存在不是静态分析的方法(例如注解),它们可以被用于考虑本地代码和反射行为。II.可变性分析为决定变量的可变性,应该能够分析所有可以修改它的状态的方法。这里介绍的分析不讨论类的实际实现的检测。因此,如果它可以被表示为没有方法能够修改它的状态的话,一个变量将标识为不可变的。一个特定变量的所有修改符/存取符的可用性依赖于该分析的范围。两个著名的极端情况如下封闭世界分析范围,其中,所有符号引用都引用被分析的类,且运行时间调用的所有可能的目标都在分析类中定义。开放世界分析范围,其中分析类的任何任意集。这类分析也称为组件分析。在封闭世界处理中,可变性分析将识别变量状态的直接修改符的集合。相反,开放世界可变性分析还识别利用分析范围外部的代码给可能的修改暴露变量的情况,并保守地将这种变量分类为可变的。方便开放世界分析的变量封装和它的破坏的概念定义如下如果对从该变量可到达的对象的所有引用都由在该分析范围之内的代码定义的话,则说一个变量是被封装的。如果该指令可以引起从该变量可到达的一个可变对象成为可对该分析范围外部的代码访问的话,则说变量的封装被在被分析的方法中的一条指令破坏。注意,不可变对象的暴露不意味封装的破坏,因为由定义知,封装仅与可变状态相关。A.可变性子分析可变性分析细分为两个主要部分,或子分析,如图4所示,说明如下使用该分析范围内类中的方法对一个变量的状态的可能的修改。在状态修改分析内的子分析检测●值修改-由在该范围内的代码对变量值状态的修改(步骤410)●对象修改-由在该范围内的代码对被引用对象状态的修改(步骤420)使用封装分析来决定从该分析范围外部,亦即通过在不是被分析组件的一部分类中定义的方法,对一个变量状态的可能的修改。在封装分析内的子分析检测●变量可访问性-从分析范围外部对该变量值状态的修改(步骤430)●对象可访问性-变量在它的初始化点不被封装(步骤440)●变量封装的破坏(步骤450)每一子分析处理引起变量可变性的一个情况系列,其中一些并非细微地被感知。例1说明几个这种情况。假定分析范围包括类例子和JavaAPI类。例1publicclassSample{/*****************************************************从该组件外部可访问的字段******************************************************/publicObjectanObject;//变量和引用的对象//是可访问的publicfinalint[]anArray={1,2,3};//引用的对象//是可访问的/*************************************专用字段**************************************/privateVectorprivateData;/*****************************************************引起privateData的被引用的对象的**可访问性的构造程序******************************************************/publicsample(){privateData-newVector();privateData.add(anArray);//anArray是一个//可访问的变量}publicSample(Objectdata){privateData-newVector();privateData.add(data);//从外部引用的数据//}/******************************************************引起privateData修改的方法******************************************************/publicvoidresetData(){privateData-newVector();//值被修改}publicvoidremoveData(){privateData.removeAllElements();//值不改变//状态被修改}/******************************************************破坏privateData封装的方法******************************************************/publicvoidaddData(Objectdata){privateData.add(data);//参数成为状态的//一部分}publicObject[]getData(){returnprivateData.toArray();//返回状态的//可变部分}publicbooleanisEqual(Vectorv){returnv.equals(privateData);//传递状态的一部分//给一个外部方法}publicvoidexposeData(){anObject-privateData;//以可访问变量//给状态的一部分//作为入口}publicvoidexposeData(Object[]array){array=privateData.elementAt(0);//以一个参数//作为入口}publicObject[]exposeData(inti){Object[]array-newObject[1];array-privateData.elementAt(i);returnarray;//以一个返回的对象//作为入口}}下面解释例1中的可变性情景。状态修改子分析●值修改方法resetData()设定privateData中的一个新值。●对象修改两个方法removeData()和addData()不改变privateData的值,但是修改由它引用的矢量对象。封装子分析●变量可访问性anObject既是非最后的也是非专用的,因此它的值状态可以从分析范围外部修改。●对象可访问性因为两个字段都是非专用的由anObject和anArray引用的对象是可访问的;anArray引用是一个可变数组,而anObject可以引用一个可变对象。这些对象的状态可以从分析范围外部修改。privateData在两个构造程序完成时未被封装。在Sample()中,privateData状态一部分的一个可变对象的引用可以由分析范围外部的代码通过anArray获得。随后可以使用这一引用来修改privateData的状态。在Sample(Object)的场合,对一个参数的引用在由构造程序调用者定义的变量中保持,它不必在被分析的组件内。这一替换入口(alias)以后可以被用来修改privateData的状态。●变量封装的破坏addData(Object)接受一个成为privateData状态一部分的对象。因为这一方法可以从分析范围外部调用且它的参数可以是可变对象,因此privateData的封装可以被破坏。相似地,exposeData(Object[])可以从分析范围外部调用,且privateData状态一部分成为该参数状态的一部分。getData()和exposeData(int)可以从分析范围外部调用。在这两种方法中,返回对象的状态包含部分privateData的状态。isEqual(Vector)作为参数传递privateData状态的一部分被虚拟方法调用。被调用的方法可以驻留在分析范围之外。ExposeData()引起在privateData和可访问变量anObject之间状态的共享。下面,引入高级数据流算法来执行保守静态组件分析。可变性分析根据可以在运行时间期间产生的变量和它们的类型计算关于代码可能行为的信息。B.高级可变性分析算法该分析的范围由形成一个Java组件分类文件的一个给定集合标识。每一分类文件对应于一个被分析的类或接口。该范围是开放的,所以一个给定的分类文件可以包括对其分类文件在分析范围之外的那些类或接口的引用。每当分析需要不可用交叉类全局信息时,就应用保守假设。假设分析范围外的类是可变的。假设扩展在分析范围以外的类的类是可变的,因为它们可以继承可变实例变量。相似地,每当一个被分析的方法包含方法调用(invokestatic,invokevirtual,invokespecial,invokeinterface)时,则当分析决定在分析范围以外可能驻留一个目标实现时它就应用保守假设。如上所述,如果由它实现的所有非静态字段是不可变的则一个非抽象类是不可变的。另一方面,一个(引用类型)变量的封装依赖于不可变类的已知集合。例如,如果相应于一个公共最后静态字段的类变量可以引用一个可变类的一个实例的话,则它将被认为是非封装的并因此是可变的。否则,因为由该类变量引用的每一个可能的对象是不可变的,因此该字段被认为是不可变的。于是,非静态字段和类的可变性/不可变性是独立的。因此,分析需要迭代处理。每一迭代根据一组已经决定的不可变类决定非静态字段的不可变性(和相应类的不可变性),直到到达一个固定点(例如直到在一次迭代前后分类保持相同;参见下文)。如果存在有这样的类,它们的不可变性在迭代处理期间没有建立,则它们被保守地认为是可变的。相反,静态字段(类变量)的可变性/不可变性不影响类的可变性,它在知道可变/不可变类的集合后计算。每一被分析的非抽象类和它的每一个实现的字段在算法执行期间被分为可变的、不可变的、或未决定的。直觉上,未决定的分类指示进一步的分析(已经分类多数类为可变的或不可变的)将最终改变该分类为可变的或者不可变的。分析用户给算法提供分类为可变的类和字段的一个(可能为空的)集合和分类为不可变的类和字段的一个(可能为空的)集合。算法以可变和不可变类和字段的一个给定集合开始。在分析范围内的其它类和字段标记为未决定的。例如,(广泛使用的)类java.lang.string需要使用字节码分析和本地代码分析的复杂技术以便恰当建立它的不可变性。这样,如果该类是分析范围的一部分,则它通常期望被初始分类为不可变的,以便为其它类获得更准确的结果。另外,如果分析的结果不包含一个被分析类的所有上类,则用户可以提供要由该类实现的非静态字段的完全表。在算法完成时每一类和每一静态字段被分类为可变的或不可变的。1)决定一个确定字段的可变性在本发明的优选实施例中,在算法中使用子例程TestField根据一组可变的、不可变的和未决定的类决定一个给定的未决定字段的可变性。输入字段由它的名字或说明类指定。对于一个非静态字段,还提供实现类。该子例程使用类可变性信息(其从类的分类得出)来设定给定字段的分类为可变的或不可变的,或保留其为未决定的。有可能出现字段不能被分类为不可变的,但是如果多个当前被分类为未决定的类被重新分类为不可变的话,则可以被分类为不可变的。在类可变性信息不足的场合,一个字段的分类为未决定的。如果每一个非抽象类被分类为可变的或不可变的(当TestField为静态字段被调用时就是这种情况),则在TestField完成时该字段被分类为可变的或不可变的。注意,为使该子例程决定给定未决定字段的可变性,应该引用相应于该字段的初始化点。如果该字段是一个静态字段,则在包含类初始化程序<clinit>完成时决定初始化点。否则,初始化点定义为相应实例构造程序<init>的完成。下面概述TestField子例程的结构1.获得一个类组,其每一个分类为可变的、不可变的或未决定的2.对于对应于Afield的每一个变量,测试是否满足下述条件A.值修改值状态可以在初始化点后由可以被调用的方法修改B.对象修改被引用的对象的状态可以在初始化点后由可以被调用的方法修改C.变量可访问性值状态可以从分析范围外部修改D.对象可访问性变量在它的初始化点处可以不被封装E.变量封装的破坏变量的封装可以在初始化点后由可以被调用的方法破坏3.如果不满足A-E中任何一条,则分类该字段为不可变的4.否则,如果当前类可变性信息不足,则保留该字段的分类为未决定的5.否则,分类该字段为可变的2)决定所有组件的字段和类的可变性下面说明使用TestField子例程建立类和字段的可变性的主迭代处理。获得某些字段和类的初始分类为可变的或不可变的,暂时分类所有其它字段和类为未决定的。1.do(循环)/*决定类和非静态字段的可变性*/2.foreverynon-abstractclass(对于每一非抽象类)classifiedasundecided(分类为未决定的)/*决定由类实现的非静态字段的可变性*/3.ifthefulllistofnon-staticfieldsimplementedbytheclassisunknown(如果由该类实现的非静态字段的完全表不知道)/*也许有由该类实现的可变非静态字段*/4.classifytheclassas(分类该类为)mutable;skiptothenextclass(可变的;跳到下一类)5.ifthereexistsanon-staticmutablefieldimplementedbytheclass(如果存在一个由该类实现的非静态可变字段的话)6.classifytheclassas(分类该类为)mutable;skiptothenextclass(可变的;跳到下一类)7.foreachnon-staticundecidedfieldAfieldimplementedbytheclass(对于由该类实现的每一个非静态未决定的字段Afield)TestField(Afield)8.ifAfieldisclassifiedasmutable(如果Afield被分类为可变的)9.classifytheclassas(分类该类为)mutable;skiptothenextclass(可变的;跳到下一类)/*由该类实现的所有非静态字段要么是未决定的,要么是不可变的*/10.ifallnon-staticfieldsimplementedbytheclassareimmutable(如果由该类实现的所有非静态字段都是不可变的)11.classifytheclassas(分类该类为)immutable(不可变的)/*for结束*/12.untilthesetofclassesclassifiedasundecidedhasnotbeenreducedinthecurrentiteration(直到在当前迭代中被分类为未决定的类的集合未减少)/*到达一个固定点*/13.foreveryclassclassifiedasundecided(对于每一分类为未决定的)14.classifytheclassasmutable(分类该类为可变的)/*决定静态字段的可变性*/15.foreveryanalyzedclassorinterface(对于每一被分析的类或接口)16.foreverystaticundecidedfieldAfielddeclaredwithintheclass(对于在该类内说明的每一静态未决定的字段Afield)TestField(Afield)III.可变性分析器工具在本部分中,说明执行静态可变性分析的可变性分析器工具。该工具对一个给定的Java组件执行开放世界分析,且分类该组件中的每一个静态字段和每一个类为可变的或不可变的。作为其输出,该工具为在该组件中被分类为可变的那些类和字段产生一个可变性原因列表。特别的,对于每一个静态字段,该工具报告一个在TestField中定义的、不为该字段保存的条件(A-E)列表,还带有附加信息。例外是对于条件D和E;如果不满足这些条件的任何一个,则报告同样的可变性原因。理由是为两个条件所执行的处理非常相似。A.TestField实现该工具的主要目的是运行非常大的组件。在该实现中特别强调可缩放性设计。作为结果,开发出不同的TestField子例程,一个用于静态字段,另一个用于非静态字段。TestField的两种实现的分析不同,它们使用测试条件A-E,其在前一部分详细说明。表1说明这些不同。表1可变性分析器工具中的TestField变化为了效率的理由,执行一系列子分析,每一个处理全部代码和抽取每一被分析方法的信息,和后来积累的所有相关字段的信息。当为第一次需要由一个子分析计算的数据时,激活该子分析;这一信息在连续调用TestField期间被重新使用。用于非静态字段的TestField子例程不重新分析为每一给定的实现字段,这种方法在高级算法中建议使用。代替的是子例程计算字段的一个保守分类为可变的或不可变的,它对该类的所有实现有效。用于静态字段的TestField子例程使用一些复杂的子分析,其中一些需要过程间的迭代,B.可变性分析器结构在本发明的优选实施例中,可变性分析器实现使用作为Toad的一部分实现内核库,该Toad是一种后生产环境,它允许关于一个运行的应用程序的动态信息共聚,带有从组成它的类收集的静态信息。Toad系统可以从IBMAlphaworks网站(http//www.alphaworks.ibm.com/tech/toad)下载。Toad环境是作为为一组内核库和监视、理解、和优化Java应用程序的工具的伞框架开发的。特别是,CFParse库允许用户读和写分类文件以及编辑它。JAN库通过分析一组分类文件收集和操作关于Java组件(例如应用程序,小程序,或服务小程序)的静态信息,并有效构造该组件的引用、层次结构、调用图表。可变性分析器结构包括三层,其在图1表示内核库,每一个提供组件的一个特别的抽取。实用工具模块,每一个执行一个假定用于几个环境中的分析。可变性子分析,每一个服务来测试一个或者多个TestField条件。1)内核库CFParse提供反应一个特定分类文件的结构信息。数据流分析需要控制流的一些更高级抽象,或者在过程内的层次上(过程内控制流图表),或者在过程间层次上(调用图表)。在这一抽象的上面,实现两个另外的内核库,每一个都是用于数据流分析的引擎过程内引擎用于迭代计算一条指令对与在该方法框架上的位置关联信息的影响(操作数堆栈和本地变量数组)。过程间引擎用于计算一个方法对与在该方法完成后保留活动的变量关联信息的影响。注意,在过程间分析期间,可以处于分析范围以外的一个被调用方法的影响应该保守地估计。在优选实施例中,该工具假定,任何虚拟调用(invokevirtual或invokeinterface)可以在分析范围以外具有可能的目标实现。这是对该分析的保守性的主要来源。2)实用程序在上述内核库以外,还实现一组实用程序分析类型分析由两种TestField子例程使用作为用于条件B、D、E测试的一部分。对于每一个被分析的方法,类型分析为每一指令和为每一帧位置识别该位置可能类型的集合。该分析区分已知被引用的对象的确切运行时间类型的情形和知道运行时间类型到指定兼容性程度的情形。该分析还考虑辖域事项。特别是,如果一个字段可以从分析范围外部修改,则它的类型被保守地假定已知与说明的类型到指定兼容性的程度。该分析使用过程内引擎。可到达性分析仅使用静态字段的TestField子例程版本来为其它子分析基础的测试条件B、D、E作为。例如,为判定一个类的封装是否被破坏,使用可到达性分析来决定其正被存储或返回对象的引用是否可以从一个静态字段到达。相似地,为决定一个类变量的状态是否可以由一个putfield指令修改,使用可到达性分析来决定该被修改变量是否可从一个静态字段到达。对于每一个被分析的方法,可到达性分析为每一条指令和每一引用可变对象的帧位置识别一个退出(escaping)对象和类变量集合,该对象从之可以到达。退出对象集合包括可从方法参数和返回对象到达的对象。注意,忽略不可变对象的可到达性关系。可变性由作为本分析参数的一个不可变类型表来决定。该分析一并使用过程间和过程内引擎。3)子分析可变性分析器(其在图1中说明)的下一层是子分析集合值修改使用两个TestField子例程来测试条件A。对于每一个被分析的方法,值修改分析识别其相应实例变量和类变量在该方法内设定的字段的集合。有三种情形需要区别被分析的方法是类初始化程序(<clinit>)除非该字段在当前初始化下的类中说明,由putstatic指令影响的字段被加在被修改的字段集合上。由putfield指令影响的字段总加在该集合上。被分析的方法是实例构造程序(<init>)由putstatic指令影响的字段总被加在被修改的字段的集合上。除非可以证明,相应变量属于当前构造下的对象,增加由putfield指令影响的字段。其它对于每一个putfield/putstatic指令,由这些指令影响的字段加在被修改的字段集合上。本分析使用过程内引擎。对象修改使用TestField子例程的静态字段版本来测试条件B。对于每一被分析的方法,状态修改分析识别引用类型静态字段和方法参数的集合,他们引用对象的状态可以由本方法修改。对于每一putfield和xastore指令,该分析查阅可到达性分析以决定正被存储的对象是否可从一个静态字段或方法参数到达。注意,本分析对于初始化方法(<init>或<clinit>)不做例外;例如,如果一个静态字段在相应的类初始化方法期间首先被分配给一个对象,且随后修改该对象的状态,则本分析将它为状态修改来识别。该分析使用过程间和过程内引擎和类型和可到达性分析。变量可访问性使用TestField子例程的两个版本来测试条件C。对于每一个被分析的字段,变量可访问性分析识别该变量的值是否可以从分析范围外部修改。当前的实现仅根据语言定义的访问限制。于是,一个非专用和非最后的字段被标识为可访问的。在其它实施例中,通过考虑运行时间访问限制和另外的辖域信息可以改进这一分析。对象可访问性和封装的破坏使用TestField子例程的静态字段版本来测试条件D和E。对于每一个被分析的方法,封装分析识别在完成该方法时可以不被封装的引用类型静态字段和方法参数的集合。除非存在一个从该变量可到达的可变对象封装的定义视一个变量为被封装的,其可从分析范围外部访问。在本优选实施例中实现更为保守,并视建立对从该变量可到达的可变对象的任何非本地引用为该变量封装的破坏。这是因为跟踪非本地引用是十分困难的。非本地存储操作(putfield/putstatic/asstore)或返回引起引用该存储对象的任何变量封装的破坏。由putfield或putstatic指定一个非封装的对象破坏存储该引用的变量的封装。在优选的实施例中,条件D和E的测试结合为一个单一分析,因为这两个处理需要很多同样的信息。该分析使用过程间、过程内引擎、类型和可到达性分析。C.结果根据优选实施例工具的结果通过把它们与下面说明的基于访问的算法得到的结果进行比较来评估。两种算法都以被分类为不可变的类java.lang.String开始。基于访问的方法不需要任何对方法体的处理,并可以通过使用核心Java反射机构实现。TestComponent子例程保留不变,在条件A-E的TestField中的测试如下(A)值修改字段是非最后的(B)对象修改字段的说明类型是数组类型、或非最后类、或可变类(C)变量可访问性字段是非专用的或非最后的(D)对象可访问性字段的说明类型是数组类型、或非最后类、或可变类(E)变量封装的破坏字段的说明类型是数组类型、或非最后情形、或可变类使用来自Java2JDK1.2版本的运行时间库rt.jar来说明这一方法的好处。选择该库是因为rt.jar非常大(>10.2Mb)且与描述相当不同的编码风格集合。图2给出为这两个算法的可变和不可变静态字段的分布。该图表示出识别为不可变的字段数目的增长。注意,识别最后基元静态字段为不可变十分简单,并且它们由忽略来自本地代码或通过反射违反对Java访问规则的任何工具以同样的方式处理。非最后非专用静态字段在不考虑运行时间可访问性的每一个分析中将被识别为可变的。因此,改进来自于减少其它可变静态字段的数目。在其它实施例中,可以增强这一工具,使得两类可变静态字段的大小进一步减小。在分类字段为可变的或不可变的以外,可变性分析器提供诸如可能的修改代码的位置关于可变性原因的信息。可以使用这一信息来修改用户代码,以便使一定字段为不可变的。表2提供为在rt.jar中的每一可变性原因报告的字段数。表2从表2看出的一点是报告状态修改和封装被破坏具有大量字段数,且在这两个原因之间呈现出的高的相关性。这与在处理虚拟方法中使用的非常保守的方法有关。可以应用类型分析和包访问限制来减少这一过保守性。期望这一改进大大减少报告的状态修改和封装被破坏的字段数。由该工具报告为直接可修改的或可访问的(非最后非专用字段,非专用可变类型字段)大多数字段事实上是具有受限访问包中的缺省范围字段。当考虑运行时间访问限制时,期望这些原因的报告数目降低到零。经验表明,在现有代码中,大多数静态字段归于下述两类之一编译时间常数(亦即最后的基元或最后的Java.lang.String)可变字段(忽略运行时间限制,使得非专用非最后字段被认为是可变的)。存在相对少的不可变字段,它们不是编译时间常数。该工具在一个大的内部IBM体系(连同运行时间库约2.4Mb,4643个类)上运行,包含多个库、小程序、和服务小程序。这一体系包括3553个静态字段,其中2324个是编译时间常数。在剩余的1229个字段中,992个字段是可变的,这是因为要么它们是非最后和非专用的,要么因为它们的值状态可以被修改。在剩余的237个字段中,大于三分之二的字段被我们的工具识别为不可变的。开发者可以使用由可变性分析器产生的识别可变性原因修改代码,以便避免可能危险的共享全局状态。这一特征是这一工具所独特的。在实现该工具期间,主要关心的是它的可缩放性。特别关心的是需要过程间迭代的子分析可到达性分析、对象可访问性分析和封装破坏分析和状态修改分析。在实践中,该工具被证明是有相当可缩放的。该工具在具有128MbRAM的PentiumIII500上使用SunJVM1.3.0rcl-T运行。全rt.jar的分析时间约为20分钟。虽然该分析需要过程间处理,但是在实际中它在问题大小上本质上是高效和几乎是线性的。这可以从图3看出,图3表示对rt.jar不同的部分的分析结果。IV.结论如前面所强调的,根据本发明的优选实施例的分析设计主要支持开放世界分析。在一般场合,这需要所有被认为可从分析范围外部访问的非专用字段和方法。然而,在实际中,存在一定的环境,其中字段和方法的可访问性可能较为受限制。例如,组件可以被感知为一个Java应用程序,它期望在一个JVM中作为单一组件运行。在这种场合,除了该应用程序由之开始运行的单一“主”方法,没有用户定义的方法(与JDK方法相比)应该被认为是可从被分析的组件外部访问。这种信息将相当大地减少组件调用图的大小。结果,由可变性分析器报告的可变性原因的数目将大大减少,且更多的字段被识别为不可变。一般说,关于该组件可以其执行的那些方法的附加信息将减少可访问方法的集合。可以给可变性分析器提供这种信息作为元数据。运行时间解析过程决定获得访问的实际实例变量或类变量,该过程受运行时间访问限制。正是SecurityManager负责限制运行时间的可访问性。一个特别的运行时间访问限制来自包密封,亦即一个一定包的特征告诉在它内的所有类必须来自同一JAR文件。与上面讨论的元数据的场合相似,关于密封包的信息将限制字段或方法的可访问性抽取。期望当前被判定为可变的541个非专用非最后rt.jar字段的大多数将被判定为不可从该组件外部访问,这是因为rt.jar的两个包之外的所有包被认为是密封的。在可变性分析器的另一个实施例中,将实现一个类方法,它使用这两类可访问性信息。根据本发明的优选实施例的可变性分析器本质上是保守的。在当前版本中的保守性其主要来源来自下面的事实,即该分析假定每一虚拟调用可由一个在被分析组件外部定义的方法解决。这意味着在这种调用传递的参量被认为是可被修改的。在另一个实施例中,可以在识别一定的虚拟调用的意义上优化组件调用图,对于这些场所所有可能的目标实现可以驻留在分析范围之内。另外,关于可访问性限制的信息,如上所述,可以进一步用来为更好的调用解析。可以使用密封信息来识别密封的调用,即其可能的目标被限制到一个包且可以在分析时间被完全决定的调用。已经证明,在rt.jar中的大约一半密封包中对非最后方法的虚拟调用5-60%被识别为密封的。虽然本发明的优选实施例已经在改进的集成性、安全性、和可缩放性方面有利的可变性环境中予以介绍,但是可变性信息还有其它使用,它影响这一事实,即一定的字段/对象的状态不随时间变化。因为这一点,可以进行优化,以改进运行时间系统的性能且使测试变得更可以跟踪。下面列出本发明一些可能的使用和它的好处。在只读存储器(ROM)中保存常数。为改进Java的可缩放性和性能,常常希望在ROM中保存已知是常数的对象。这是所有类型(flavor)的Java高端服务器所希望的,它们希望快速起动JvM以便运行一个事务处理和退出;嵌入式系统,在这里RAM是稀有资源;和台式机,在这里希望能够以最少开销快速起动Java应用程序。网络效果是对象放在只读存储器中,节省堆(heap)中的空间,避免堆垃圾收集的额外工作。分布共享存储器(DSM)。DSM效率中的重要因素是在处理器之间适当分配对象。识别不可变对象允许其在DSM簇中的每一个处理器上建立复制品。这消除了以相当大的从一个处理器向另一个处理器传输对象费用的需要。另外,可以利用关于不可变对象的信息来避免在多线程和分布式环境中费用很高的相干性和同步方面的开销。并发性。在对称多处理器(SMP)或非统一存储器访问(NUMA)系统上的并发程序执行引入安全和生存的概念。并发性的设计需要避免共享状态的非同步改变。这种同步引入管理开销费用。这一开销对于已知是不可变的对象可以避免。不可变对象识别的一个有趣的具体应用例子是Doligez和G.Gonthier的世代垃圾收集器,“为多处理器系统可移植的、不引人注目的收集”,在关于编程语言原理的第21届ACM年会会议记录中,ACMSIGPLAN通知,ACM出版社,第113-123页,1994年;和Doligez和X.Leroy,“用于ML的多线程实现的并发世代垃圾收集器”,关于编程语言原理的第20届ACM年会会议记录,ACMSIGPLAN通知,ACM出版社,第113-123页,1993年。这一高效收集器只在本地新一代子堆中分配不可变对象。关键的思想是不可变对象可以被复制而不影响程序语义。本发明的优选实施例中的算法可以用来识别Java中的不可变对象,因此推动这种世代垃圾收集器的使用。组件说明。在一个组件的行为特征描述中可变性信息十分有用。这一特征描述增强了组件的接口说明,且在方便组件的可重用性方面十分有用。对参量的这一传统的先决和后置条件说明特性通过从组件的全局状态的可变性的引用引入的信息加以放大。测试覆盖范围。软件测试使用覆盖范围判据来决定一个测试集的有效性。数据流测试判据通常基于“def-使用”信息,这在A.S.Parrish和S.H.Zweben发表的“关于在所有用户、所有DU路径、和所有边缘测试判据之间的关系”-中表示,该文发表在IEEETransactionsonSoftwareEngineering,第21卷,第12期,1995年12月。在传统def-使用判据中有两个主要的问题。一个出现在现实生活应用中的环境中,在这里该测试集的大小作为缓和信息变得太大。另一个是测试库,在这里必须考虑在分析范围外方法的效果。可以使用可变性信息来定义比在库中已知的那些弱、但是更可缩放和可应用于现实世界的判据。另外,与现有判据相对照,提出的可变性判据将覆盖这样的位置,这里除了发现该变量被内部修改的位置以外一个变量变为暴露给外部修改。值范围。通常使用缺省边界类型值形成测试情形值。在现实应用程序中的域值非常大。在实际中,这限制了测试模型的可应用性。识别常数对象大大减小了域值问题,从而方便了有效使用该模型。Java中可变性的定义从未专门正式提出。本发明的优选实施例介绍了可以用作为在这一领域中进一步研究工作基础的定义,且说明了以便自动检测可变的和不可变的变量、字段、对象和类的静态分析的新颖方法。本发明的一个主要贡献是处理开放世界分析,从而能够接受分析范围的任何Java组件。可变性分析器工具的结果演示了所述方法的强度,且强化了定义的集成性。尽管已经使用了开放世界分析,但是可变性分析器成功地为Java运行时间分类类变量、实例变量和类。一个驱动优选实施例实现的核心设计决定是使用基本内核库,诸如CFParse和JAN,且为过程内和过程间分析引入通用引擎。代码设计为可缩放和适合多级静态分析结构,所以可以使用实用程序和子分析并将其扩展以处理非可变性特征描述的特性。在一些场合静态分析被限制。因此,对于该分析不能静态检测的特性,在其它实施例中设置了智能注释,以便在运行期间检测这些情形。这一点可以通过使用CFParse内核库来分析、编辑和注释分类文件而实现。另外,本发明的其它实施例将引导分析的扩展,诸如间隔不可变性分析以决定变量在一定间隔上的不可变性,如在一个特定方法的调用期间,与允许插入子组件的可变性分析的集成结果以获得全组件分析。模块不可变性分析可以增强从一定初始化点开始的不可变性的定义,以便覆盖懒惰的初始化,亦即,变量只设定一次,而在该类或实例的初始化期间不再需要的情形。虽然引用本发明特定优选实施例表示和说明了本发明,但是熟悉本
技术领域
的人理解,其中在不离开由在所附权利要求所定义的本发明的精神和范围可以进行形式和细节上的各种改变。权利要求1.一种检测一个程序组件中变量、对象、字段、和类的可变性的方法,所述组件用面向对象的编程语言书写,包括步骤判定在该程序组件中的任何变量是否可以经受第一类型状态修改,所述第一类型状态修改由该程序组件中的至少一种方法进行;执行封装分析以判定在该程序组件中的任何变量是否可以经受第二类型的状态修改,所述第二类型状态修改由不在该程序组件中的至少一种方法进行;其中,如果在一个变量初始化以后它的状态曾经改变的话则所述变量是可变的,所述变量的状态是它的值连同任何引用的对象的状态;其中,如果在一个对象初始化以后它的状态曾经改变的话则所述对象是可变的,所述对象的所述状态是所有相关变量的状态的集合;其中,如果对应于一个字段的任何变量是可变的则所述字段是可变的;其中,如果由一个类实现的任何实例字段是可变的则所述类是可变的。2.权利要求1所述方法,第一类型状态修改决定步骤包括步骤检测在所述每一变量中保持值的可能的第一类型状态修改;检测由所述每一变量引用的任何对象状态的可能的第一类型状态修改。3.权利要求1所述方法,封装分析步骤包括步骤检测在所述每一变量中保持值的可能的第二类型状态修改;检测由所述每一变量引用的任何对象状态的可能的第二类型状态修改,任何对象状态的可能的第二类型状态修改发生在初始化的点处;检测变量封装的可能的破坏;其中,如果对从一个变量可到达的对象的所有引用都在该程序组件中定义的话则该变量是被封装的;其中,如果在该程序组件中的一个方法引起一个从该变量可到达的可变对象变得可由至少一种不在该程序组件中的方法访问的话则变量封装被破坏。4.权利要求1所述方法,其中,所述方法在Java环境中实现,所述任何实例字段是非静态字段,所述变量是类变量或实例变量,每一所述类变量在它相应的<clinit>方法完成时被初始化,每一所述实例变量在它相应的<init>方法完成时被初始化。5.权利要求1所述方法,进一步包括步骤识别由于检测可变全局变量或对象的分离错误。6.权利要求1所述方法,进一步包括步骤识别这样的字段和对象,它们因为所述被识别的字段和对象不在检测到的可变字段和对象的集合中而可以被判定为是常数。7.一种检测在一个程序组件中类的可变性的方法,所述组件用面向对象的编程语言书写,包括步骤获得一组类,每一所述类被分类为可变的、不可变的、和未决定的其中之一;测试每一未决定的类,所述测试包括子步骤测试被测试的所述未决定的类中的每一字段,所述测试包括子步骤判定相应于所述每一字段的任何变量是否可以经受第一类型的状态修改,所述第一类型状态修改由在所述组件中的至少一种方法进行;执行封装分析以判定对应于所述每一字段的任何变量是否可以经受第二类型的状态修改,所述第二类型状态修改由不在所述组件中的至少一种方法进行;如果未发现可能的第一类型或第二类型状态修改的话则分类所述每一字段为不可变的;如果类可变性信息不足的话则分类所述每一字段为未决定的;否则分类所述每一字段为可变的;如果在所述未决定类中的任何字段是可变的则重新将所述未决定的类分类为可变的;如果在所述未决定类中的所有字段是不可变的则重新将所述未决定的类分类为不可变的;重复所述测试每一未决定的类步骤,直到在重复所述测试步骤后未决定的类的数目和重复所述测试步骤前的未决定的类的数目相同;重新将剩余的未决定的类分类为可变类。8.一种检测在一个程序组件中类的可变性的方法,所述组件用面向对象的编程语言书写,包括步骤获得一组类,每一所述类被分类为可变的、不可变的、和未决定的其中之一;测试每一未决定的类,所述测试包括子步骤测试被测试的所述未决定的类中的每一实例字段,所述测试包括子步骤判定相应于所述每一实例字段的任何变量是否可以经受第一类型的状态修改,所述第一类型状态修改由在所述组件中的至少一种方法进行;执行封装分析以判定对应于所述每一实例字段的任何变量是否可以经受第二类型的状态修改,所述第二类型状态修改由不在所述组件中的至少一种方法进行;如果未发现可能的第一类型或第二类型的状态修改的话则将所述每一实例字段分类为不可变的;如果类可变性信息不足的话则将所述每一实例字段分类为未决定的;否则将所述每一实例字段分类为可变的;如果在所述未决定的类中的任何实例字段是可变的则重新所述未决定的类分类为可变的;如果在所述未决定的类中的所有实例字段是不可变的则重新所述未决定的类分类为不可变的;重复所述测试每一未决定的类步骤,直到在重复所述测试步骤后未决定的类的数目和重复所述测试步骤前的未决定的类的数目相同;重新将剩余的未决定的类分类为可变类。9.权利要求8所述方法,第一类型状态修改判定子步骤包括步骤检测在所述每一变量中保持的值的可能的第一类型状态修改;检测由所述每一变量引用的任何对象的状态的可能的第一类型状态修改;其中,如果在一个对象初始化以后它可以改变的话,则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话,该变量是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态。10.权利要求8所述方法,执行封装分析子步骤包括步骤检测所述每一变量值的可能的第二类型状态修改;检测由所述每一变量引用的任何对象状态的可能的第二类型修改,任何对象状态的所述可能的第二类型状态修改发生在初始化点;检测变量封装的可能的破坏;其中,如果在一个对象初始化以后它可以改变的话则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话则该变量是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态;其中,如果对从一个变量可到达的对象的所有引用都在所述组件中定义则该变量是被封装的;其中,如果在该程序组件中的一个方法引起一个从变量可到达的可变对象变得可由至少一个不在所述组件中的方法访问的话则变量封装被破坏。11.权利要求8所述方法,其中,该方法在Java环境中实现,对应于所述每一实例字段的所述每一变量是非静态变量,且每一非静态变量在它相应的<init>方法完成时被初始化。12.权利要求8所述方法,另外包括步骤如果一个对象是一个可变类的实例,则它被识别为是可变的;如果一个对象是一个不可变类的实例,则它被识别为是不可变的;识别这样的字段和对象,它们因为所述被识别的字段和对象不在检测到的可变字段和对象的集合中而可以被决定为是常数。13.权利要求8所述方法,另外包括步骤测试在每一类中的每一未决定类字段的可变性。14.权利要求13所述方法,另外包括步骤识别由于检测到的可变类字段的分离错误。15.权利要求13所述方法,测试在每一类中的每一未决定类字段的可变性的步骤包括子步骤判定对应于所述每一未决定类字段的任何变量是否可以经受第一类型的状态修改;执行封装分析以判定对应于所述每一未决定类字段的任何变量是否可以经受第二类型的状态修改。16.权利要求15所述方法,其中,判定对应于所述每一未决定类字段的任何变量是否可以经受第一类型的状态修改子步骤包括步骤检测在所述每一变量中保持值的可能的第一类型状态修改;检测由所述每一变量引用的任何对象的一个状态的可能的第一类型状态修改;其中,如果在一个对象初始化以后它可以改变的话则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话则它是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态。17.权利要求15所述方法,其中,执行封装分析以决定相应于所述每一未决定类字段的任何变量是否可以经受第二类型状态修改子步骤包括步骤检测所述每一变量值的可能的第二类型状态修改;检测由所述每一变量引用的任何对象的一个状态的可能的第二类型状态修改,任何对象的一个状态的所述可能的第二类型状态修改发生在初始化点;检测变量封装的可能的破坏;其中,如果在一个对象初始化以后它可以改变的话则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话则它是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态;其中,如果对从一个变量可到达的对象的所有引用都在所述组件中定义则它是被封装的;其中,如果在该程序组件中的一个方法引起从一个变量可到达的一个可变对象变得可由至少一个不在所述组件中的方法访问的话则变量封装被破坏。18.权利要求13所述方法,其中,该方法在Java环境中实现,对应于所述每一未决定类字段的所述变量是静态变量,且每一静态变量在它的相应的<clinit>方法完成时被初始化。19.一种检测在一个程序组件中类和类变量的可变性的方法,所述组件用面向对象的编程语言书写,包括步骤获得一组类,每一所述类被分类为可变的、不可变的、和未决定的其中之一;测试每一未决定的类,所述测试包括子步骤测试被测试所述未决定类中的每一实例字段的可变性;如果未发现可能的状态或封装分析修改的话则将一个实例字段分类为不可变的;如果类可变性信息不足的话则将一个实例字段分类为未决定的;否则分类一个实例字段为可变的;如果在所述未决定的类中的任何实例字段是可变的则重新将一个未决定的类分类为可变的;如果在所述未决定的类中的所有实例字段是不可变的则重新将所述未决定的类分类为不可变的;重复对每一未决定的类步骤的所述测试,直到在重复所述测试步骤后未决定的类的数目和重复所述测试步骤前的未决定的类的数目相同;重新将剩余的未决定的类分类为可变类;测试每一类中的每一类字段的可变性。20.权利要求19所述方法,其中,测试字段的可变性,无论所述字段是实例字段还是类字段,包括子步骤判定对应于所述被测试字段的任何变量是否可以经受第一类型状态修改,所述第一类型状态修改由在该程序组件中的至少一种方法进行;执行封装分析以判定对应于所述被测试字段的任何变量是否可以经受第二类型的状态修改,所述第二类型状态修改由不在该程序组件中的至少一种方法进行;如果未发现可能的状态修改或封装的破坏的话则将所述被测试字段分类为不可变的;如果类可变性信息不足的话则将所述被测试字段分类为未决定的;否则分类所述被测试字段为可变的。21.权利要求20所述方法,其中,第一类型状态修改判定子步骤包括步骤检测在所述每一变量中保持值的可能的第一类型状态修改;检测由所述每一变量引用任何对象的一个状态的可能的第一类型状态修改;其中,如果在一个对象初始化以后它可以改变的话则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话则它是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态。22.权利要求20所述方法,其中,执行封装分析子步骤包括步骤检测所述每一变量的值可能的第二类型状态修改;检测由所述每一变量引用任何对象的一个状态的可能的第二类型修改,任何对象的一个状态的所述可能的第二类型状态修改发生在初始化点;检测变量封装的可能的破坏;其中,如果在一个对象初始化以后它可以改变的话则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话则它是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态;其中,如果对从一个变量可到达的对象的所有引用都在所述组件中定义则它是被封装的;其中,如果在该程序组件中的一个方法引起从一个变量可到达的一个可变对象变得可由至少一个不在所述组件中的方法访问的话则变量封装被破坏。23.权利要求19所述方法,其中,所述方法在Java环境中实现,所述实例字段是非静态字段,一个实例变量在它的相应的<init>方法完成时被初始化,所述类字段是静态字段,一个类变量在它的相应的<clinit>方法完成时被初始化。24.权利要求19所述方法,另外包括步骤如果一个对象是一个可变类的实例,则它被识别为是可变的;如果一个对象是一个不可变类的实例,则它被识别为是不可变的;识别这样的字段和对象,它们因为所述被识别的字段和对象不在检测到的可变字段和对象的集合中而可以被决定为是常数。25.权利要求19所述方法,另外包括识别由于检测到的可变类字段的分离错误的步骤。26.一种设备,用于检测一个程序组件中的变量、对象、字段、和类的可变性,所述组件用面向对象的编程语言书写,包括至少一个内核库和至少一个数据流分析引擎层,用于提供该程序组件的特定抽取;至少一个实用程序模块层,用于使用至少一个数据分析引擎的结果产生基本结果;至少一个可变性子分析模块层,用于产生最后结果;其中,如果在一个变量初始化以后它的状态曾经改变的话则该变量是可变的,一个变量的状态是它的值连同任何引用的对象的状态;其中,如果在一个对象初始化以后它的状态曾经改变的话则该对象是可变的,一个对象的状态是所有相关变量的状态的集合;其中,如果相应于一个字段的任何变量是可变的则该字段是可变的;其中,如果由一个类实现的任何实例字段是可变的则该类是可变的。27.权利要求26所述设备,至少一个内核库和至少一个数据分析引擎层包括一个库,用于通过分析一组分类文件收集和操作关于该程序组件的静态信息,且用于有效构造该程序组件的引用、层次结构、和调用图。28.权利要求26所述设备,至少一个内核库和至少一个数据分析引擎层包括一个库,用于允许用户读分类文件。29.权利要求26所述设备,至少一个内核库和至少一个数据分析引擎层包括一个过程内数据分析引擎,用于迭代计算一条指令对与在一个方法框架上的位置关联的信息的影响,所述方法框架是一个操作数堆栈和一个本地变量数组。30.权利要求26所述设备,至少一个内核库和至少一个数据分析引擎层包括一个过程间数据分析引擎,用于计算一个方法对与在该方法完成时仍然存在的变量关联的信息的影响。31.权利要求26所述设备,至少一个实用程序模块层包括一个类型分析实用程序模块,用于识别为在每一方法中的每一指令和每一框架位置的可能的类型的集合。32.权利要求26所述设备,至少一个实用程序模块层包括一个可到达性分析实用程序模块,用于为每一方法识别退出对象和类变量的一个集合,从所述类变量为引用一个可变对象的每一指令和每一帧位置可到达所述可变对象。33.权利要求26所述设备,至少一个可变性子分析模块层包括一个值修改可变性子分析模块,用于为每一方法识别一组字段,它们的相应实例和类变量可以在所述每一方法内设定。34.权利要求26所述设备,至少一个可变性子分析模块层包括一个对象修改可变性子分析模块,用于为每一方法识别一组引用类型字段和方法参数,所述该组引用类型字段和方法参数引用一个对象,所述对象的状态由所述每一方法修改。35.权利要求26所述设备,至少一个可变性子分析模块层包括一个变量可访问性可变性子分析模块,用于为每一变量识别它的值是否可以由至少一个不在该程序组件内的方法直接修改。36.权利要求26所述设备,至少一个可变性子分析模块层包括一个对象可访问性可变性子分析模块,用于检测每一对象的一个状态的可能的可访问性,通过决定与所述对象关联的每一变量是否被封装进行;其中,如果对从一个变量可到达的对象的所有引用在该程序组件中定义的话则它是被封装的;其中,所述可访问性由不在该程序组件之内的至少一种方法进行。37.权利要求26所述设备,至少一个可变性子分析模块层包括一个封装破坏可变性子分析模块,用于检测封装的可能的破坏;其中,如果对从一个变量可到达的可变对象的所有引用在该程序组件中定义的话则它是被封装的;其中,如果在程序组件内的一个方法引起从该变量可到达的一个可变对象变得对不在该程序组件内的至少一个方法可访问的话则变量封装被破坏。38.一种检测一个程序组件中变量、对象、字段、和类的可变性的计算机系统,所述组件以面向对象的编程语言书写,所述计算机系统包括至少一个计算机可读存储器,包括决定在该程序组件中的任何变量是否可以经受第一类型状态修改的代码,所述第一类型状态修改由在该程序组件中的至少一种方法进行;执行封装分析以决定在该程序组件中的任何变量是否可以经受第二类型的状态修改的代码,所述第二类型状态修改由不在该程序组件中的至少一种方法进行;其中,如果在变量初始化以后它的状态曾经改变的话则所述变量是可变的,所述变量的状态是它的值连同任何引用的对象的状态;其中,如果在对象初始化以后它的状态曾经改变的话则所述对象是可变的,所述对象的所述状态是所有相关变量的状态的集合;其中,如果相应于字段的任何变量是可变的则所述字段是可变的;其中,如果由类实现的任何实例字段是可变的则所述类是可变的。39.权利要求38所述计算机系统,其中,决定任何变量是否可以经受第一类型状态修改的代码包括检测在所述每一变量中保持值的可能的第一类型状态修改的代码;检测由所述每一变量引用的任何对象状态的可能的第一类型状态修改的代码。40.权利要求38所述计算机系统,其中,执行封装分析步骤的代码包括检测在所述每一变量中保持值的可能的第二类型状态修改的代码;检测由所述每一变量引用的任何对象状态的可能的第二类型状态修改的代码,任何对象的状态的可能的第二类型状态修改发生在初始化的点处;检测变量封装可能破坏的代码;其中,如果对从一个变量可到达的对象的所有引用都在该程序组件中定义则一个变量是被封装的;其中,如果在该程序组件中的一个方法引起从该变量可到达的一个可变对象变得可由至少一种不在该程序组件中的方法访问的话则变量封装被破坏。41.权利要求38所述计算机系统,其中,所述程序组件在Java环境中实现,所述任何实例字段是非静态字段,所述变量是类变量或实例变量,每一所述类变量在它的相应的<clinit>方法完成时被初始化,每一所述实例变量在它的相应的<init>方法完成时被初始化。42.权利要求38所述计算机系统,其中,至少一个计算机可读存储器另外包括识别由于检测的可变全局变量或对象的分离错误的代码。43.权利要求38所述计算机系统,其中,至少一个计算机可读存储器另外包括识别这样的字段和对象的代码,它们因为所述被识别的字段和对象不在检测到的可变字段和对象的集合中而被决定为是常数。44.一种检测在一个程序组件中的变量、对象、字段、和类可变性的计算机系统,所述组件用面向对象的编程语言书写,该计算机系统包括至少一个计算机可读存储器,包括获得一组类的代码,每一所述类被分类为可变的、不可变的、和未决定的其中之一;测试所述被测试的未决定的类中的每一字段的代码,所述字段测试代码包括测试正被测试的所述未决定的类中的每一字段的代码,所述字段测试代码包括决定相应于所述每一字段的任何变量是否可以经受第一类型的状态修改的代码,所述第一类型状态修改由在程序组件中的至少一种方法进行;执行封装分析以决定相应于所述每一字段的任何变量是否可以经受第二类型的状态修改的代码,所述第二类型状态修改由不在所述组件中的至少一种方法进行;如果未发现可能的状态修改或封装被破坏的话则所述每一字段分类为不可变的代码;如果发现可能的状态修改或封装被破坏的话则所述每一字段分类为可变的代码;如果类可变性信息不足的话则所述每一字段分类为为未决定的代码;如果在所述未决定的类中的任何字段是可变的则重新将所述未决定的类分类为可变的代码;如果在所述未决定的类中的所有字段是不可变的则重新将所述未决定的类分类为不可变的代码;重复所述测试每一未决定的类代码,直到在重复所述测试代码后未决定的类的数目和重复所述测试代码前的未决定的类的数目相同的代码;重新将剩余的未决定的类分类为可变类的代码。45.一种检测在一个程序组件中的变量、对象、字段、和类可变性的计算机系统,所述组件用面向对象的编程语言书写,该计算机系统包括至少一个计算机可读存储器,包括获得一组类的代码,每一所述类被分类为可变的、不可变的、和未决定的其中之一;测试每一未决定的类的代码,所述测试包括测试在正被测试的所述未决定的类中的每一实例字段的代码,所述实例字段测试代码包括决定相应于所述每一实例字段的任何变量是否可以经受第一类型的状态修改的代码,所述第一类型状态修改由在该程序组件中的至少一种方法进行;执行封装分析以决定相应于所述每一实例字段的任何变量是否可以经受第二类型的状态修改的代码,所述第二类型状态修改由不在所述组件中的至少一种方法进行;如果未发现可能的状态修改或封装破坏的话则将所述每一实例字段分类为不可变的的代码;如果发现可能的状态修改或封装破坏的话则将所述每一实例字段分类为可变的的代码;如果类可变性信息不足的话则将所述每一实例字段分类为未决定的的代码;如果在所述未决定的类中的任何实例字段是可变的话则重新将所述未决定的类分类为可变的的代码;如果在所述未决定的类中的所有实例字段是不可变的话则重新将所述未决定的类分类为不可变的的代码;重复所述测试每一未决定的类代码,直到在重复所述测试代码后未决定的类的数目和重复所述测试代码前的未决定的类的数目相同的代码;重新将剩余的未决定的类分类为可变类的代码。46.权利要求45所述计算机系统,其中,决定任何变量是否可以经受第一类型状态修改的代码包括检测在所述每一变量中保持值的可能的第一类型状态修改的代码;检测由所述每一变量引用的任何对象状态的可能的第一类型状态修改的代码;其中,如果在一个对象初始化以后它可以改变的话则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话则该变量是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态。47.权利要求45所述计算机系统,其中,执行封装分析的代码包括检测所述每一变量值的可能的第二类型状态修改的代码;检测由所述每一变量引用的任何对象状态的可能的第二类型修改的代码,任何对象的一个状态的所述可能的第二类型状态修改发生在初始化点;检测变量封装的可能的破坏代码;其中,如果在一个对象初始化以后它可以改变的话则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话则一个变量是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态;其中,如果对从一个变量可到达的对象的所有引用都在所述组件中定义的话则一个变量是被封装的;其中,如果在该程序组件中的一个方法引起从一个变量可到达的一个可变对象变得可由至少一个不在所述组件中的方法访问的话则变量封装被破坏。48.权利要求45所述计算机系统,其中,程序组件在Java环境中实现,对应于所述每一实例字段的所述每一变量是非静态变量,和每一非静态变量在它的相应的<init>方法完成时被初始化。49.权利要求45所述计算机系统,其中,至少一个计算机可读存储器另外包括如果一个对象是一个可变类的实例的话的代码则识别该对象是可变的;如果是一个不可变类的实例的话的代码则识别该对象是不可变的;识别这样的字段和对象的代码,它们因为所述被识别的字段和对象不在检测到的可变字段和对象的集合中而可以被决定为是常数。50.权利要求45所述计算机系统,其中,至少一个计算机可读存储器另外包括测试在每一类中的每一未决定类字段的可变性的代码。51.权利要求50所述计算机系统,其中,至少一个计算机可读存储器另外包括用于识别由于检测到的可变类字段的分离错误的代码。52.权利要求50所述计算机系统,其中,测试在每一类中的每一未决定类字段可变性的代码包括决定相应于所述每一未决定类字段的任何变量是否可以经受第一类型的状态修改的代码;执行封装分析以决定相应于所述每一未决定类字段的任何变量是否可以经受第二类型状态修改的代码。53.一种检测在一个程序组件中类和类变量的可变性计算机系统,所述组件用面向对象的编程语言书写,包括至少一个计算机可读存储器,包括获得一组类的代码,每一所述类被分类为可变的、不可变的、和未决定的其中之一;测试每一未决定类的代码,所述测试包括测试在正被测试的所述未决定类中的每一实例字段的代码,所述实例字段测试代码包括决定相应于所述每一实例字段的任何变量是否可以经受第一类型状态修改的代码,所述第一类型状态修改由在该程序组件之内的至少一种方法进行;执行封装分析以决定相应于所述每一实例字段的任何变量是否可以经受第二类型状态修改的代码,所述第二类型状态修改由不在所述组件中的至少一种方法进行;如果未发现可能的状态修改或封装破坏的话的代码则将所述每一实例字段分类为不可变的;如果发现可能的状态修改或封装破坏的话的代码则将所述每一实例字段为可变的;如果类可变性信息不足的话的代码则将所述每一实例字段为为未决定的;如果在所述未决定的类中的任何实例字段是可变的话的代码则重新将所述未决定的类分类为可变的;如果在所述未决定的类中的所有实例字段是不可变的话的代码则重新将所述未决定的类分类为不可变的;重复所述测试每一未决定的类代码,直到在重复所述测试代码后未决定的类的数目和重复所述测试代码前的未决定的类的数目相同的代码;重新将剩余的未决定的类分类为可变类的代码;测试在每一类中每一类字段的可变性的代码。54.权利要求53所述计算机系统,其中,测试一个字段可变性的代码,不管所述字段是实例字段还是类字段,包括决定相应于所述被测试字段的任何变量是否可以经受第一类型状态修改的代码,所述第一类型状态修改由在所述程序组件内的至少一种方法进行;执行封装分析以决定相应于所述被测试字段的任何变量是否可以经受第二类型状态修改的代码,所述第二类型状态修改由不在所述程序组件内的至少一种方法进行;如果未发现可能的状态修改或封装的破坏的话的代码则将所述被测试字段分类为不可变的;如果类可变性信息不足的话的代码则将所述被测试字段分类为未决定的;否则将所述被测试字段分类为可变的的代码。55.权利要求54所述计算机系统,其中,决定任何变量是否可以经受第一类型状态修改的代码包括检测在所述每一变量中保持的值的可能的第一类型状态修改的代码;检测由所述每一变量引用的任何对象的一个状态的可能的第一类型状态修改的代码;其中,如果在一个对象初始化以后它可以改变的话则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话则该变量是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态。56.权利要求54所述计算机系统,其中,执行封装分析的代码包括检测所述每一变量值的可能的第二类型状态修改的代码;检测由所述每一变量引用的任何对象的一个状态的可能的第二类型状态修改的代码,任何对象的一个状态的所述可能的第二类型状态修改发生在初始化点;检测变量封装的可能的破坏的代码;其中,如果在一个对象初始化以后它可以改变的话则该对象的状态被修改;一个对象的状态是所有相关变量的状态的集合;其中,如果一个变量的状态在所述变量初始化以后曾经改变的话则一个变量是可变的,所述变量的状态是它的值连同任何引用的对象的一个状态;其中,如果对从可到达的对象的所有引用都在所述组件内定义则一个变量是被封装的;其中,变量封装被破坏,如果在该程序组件内的一个方法引起从一个变量可到达的一个可变对象变得可由至少一个不在所述组件内的方法访问的话。57.权利要求53所述计算机系统,其中,程序组件在Java环境中实现,所述实例字段是非静态字段,一个实例变量在它的相应的<init>方法完成时被初始化,所述类字段是静态字段,一个类变量在它的相应的<clinit>方法完成时被初始化。58.权利要求53所述计算机系统,其中,至少一个计算机可读存储器另外包括如果一个对象是一个可变类的一个实例的话的代码则识别该对象是可变的;如果一个对象是一个不可变类的一个实例的话的代码则识别该对象是不可变的;识别这样的字段和对象的代码,它们因为所述被识别的字段和对象不在检测到的可变字段和对象的集合中而可以被决定为是常数。59.权利要求53所述计算机系统,其中,至少一个计算机可读存储器另外包括用于识别由于检测到的可变类字段分离错误的代码。60.一个计算机系统,用于检测在一个程序组件中的变量、对象、字段、和类的可变性,所述组件用面向对象的编程语言书写,该计算机系统包括至少一个计算机可读存储器,包括维护可变性分析器中至少一个内核库和至少一个数据流分析引擎的层的代码,用于提供该程序组件的特定抽取;维护可变性分析器中至少一个实用程序模块层的代码,用于使用至少一个数据分析引擎的结果产生基本结果;维护可变性分析器中至少一个可变性子分析模块层的代码,用于产生最后结果;其中,如果在一个变量初始化以后它的状态曾经改变的话则该变量是可变的,所述变量的状态是它的值连同任何引用的对象的状态;其中,如果在一个对象初始化以后它的状态曾经改变的话则该对象是可变的,所述对象的状态是所有相关变量的状态的集合;其中,如果相应于一个字段的任何变量是可变的则该字段是可变的;其中,如果由一个类实现的任何实例字段是可变的则该类是可变的。61.权利要求60所述计算机系统,其中,维护至少一个内核库和至少一个数据分析引擎层的代码包括通过分析一组分类文件收集和操作关于该程序组件的静态信息的代码;用于有效构造该程序组件的引用、层次结构、和调用图的代码。62.权利要求60所述计算机系统,其中,维护至少一个内核库和至少一个数据分析引擎层的代码包括用于允许用户读分类文件的代码。63.权利要求60所述计算机系统,其中,维护至少一个内核库和至少一个数据分析引擎层的代码包括用于迭代计算一条指令对与在一个方法框架上的位置关联的信息影响的代码,所述方法框架是一个操作数堆栈和一个本地变量数组。64.权利要求60所述计算机系统,其中,维护至少一个内核库和至少一个数据分析引擎层的代码包括用于计算一个方法对与在该方法完成时仍然存在的变量关联的信息的影响的代码。65.权利要求60所述计算机系统,其中,维护至少一个实用程序模块层的代码包括用于识别为在每一方法中的每一指令和每一框架位置的可能类型的集合的代码。66.权利要求60所述计算机系统,其中,维护至少一个实用程序模块的层的代码包括用于为每一方法识别退出对象和类变量一个集合的代码,从所述类变量为引用一个可变对象的每一指令和每一框架位置可到达所述可变对象。67.权利要求60所述计算机系统,其中,维护至少一个可变性子分析模块的层的代码包括用于为每一方法识别一组字段的代码,所述字段的相应实例和类变量可以在所述每一方法内设定。68.权利要求60所述计算机系统,其中,维护至少一个可变性子分析模块的层的代码包括用于为每一方法识别一组引用类型字段和方法参数的代码,所述该组引用类型字段和方法参数引用一个对象,所述对象的状态由所述每一方法修改。69.权利要求60所述计算机系统,其中,维护至少一个可变性子分析模块的层的代码包括用于为每一变量识别它的值是否可以由至少一个不在该程序组件内的方法直接修改的代码。70.权利要求60所述计算机系统,其中,维护至少一个可变性子分析模块的层的代码包括用于检测每一对象的一个状态可能的可访问性的代码,通过决定与所述对象关联的每一变量是否被封装进行;其中,如果对从一个变量可到达的对象的所有引用在该程序组件内定义的话则一个变量是被封装的;其中,所述可访问性由不在该程序组件之内的至少一种方法进行。71.权利要求60所述计算机系统,其中,维护至少一个可变性子分析模块层的代码包括用于检测封装的可能的破坏代码;其中,如果对从一个变量可到达的可变对象的所有引用在该程序组件内定义的话则一个变量是被封装的;其中,如果在该程序组件内的一个方法引起从该变量可到达的一个可变对象变得对不在该程序组件内的至少一个方法可访问的话则变量封装被破坏。全文摘要公开了一种检测在一个任意程序组件中字段和类的可变性的系统和方法,所述程序组件用面向对象的编程语言书写。如果其内存储入一个新值的话,及如果它的任何可到达的变量是可变的话则一个变量被认为是可变的。该系统和方法使用一个静态分析算法,它可以应用于任何软件组件而不是整个程序。该分析将字段和类或者分类为可变的、或者为不可变的。为便利开放世界分析,该算法识别这样的情形,即通过在该组件以外的代码暴露变量于可能的修改,以及这样的情形,即由被分析的代码修改变量。介绍了本分析的一个实现,它集中在检测类变量的可变性,以便避免分离问题。该实现结合过程内和过程间的数据流分析,并被证明是可高度缩放的。实验结果演示出该算法的有效性。文档编号G06F9/45GK1754151SQ01815982公开日2006年3月29日申请日期2001年9月17日优先权日2000年9月21日发明者L·科维德,B·门德尔森,S·珀拉特,M·比伯斯泰恩申请人:国际商业机器公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1