特化类的依赖性驱动的共同特化的制作方法

文档序号:12287761阅读:233来源:国知局
特化类的依赖性驱动的共同特化的制作方法与工艺

本发明一般而言涉及软件开发并且更具体而言涉及在各种编程语言中任何一种语言当中的语言开发的各方面,作为一个例子,所述编程语言为诸如独立于平台的面向对象的编程语言。



背景技术:

在各种编程语言中,参数多态性(例如,泛型)可被认为是使语言更具表达性同时仍保持完全静态类型安全性的方式。参数多态性可以允许以泛型方式编写函数或数据类型,使得其可以以相同方式处理各种数据类型,而不管它们的类型不同。这样的函数和数据类型可被称为泛型函数和泛型数据类型。例如,泛型列表类可被写为List<T>,这意味着它可以是任何类型T的元素的列表,其中T与List分开指定。

当使用不提供可以是用于所有其它类型的超类型的单个类型的面向对象语言时,经常不能在不使用特定转换操作的情况下在某些类型上进行泛化,其中所述特定转换操作为诸如装箱(例如,自动将基本类型(像int)的值转换成对应包装类(像Integer)的对象)。例如,传统上JavaTM语言不允许对象和基本类型上的泛型。

参数多态性(泛型)还可以涉及代码规模、生成成本和类型特殊性之间的权衡。例如,编程语言可以支持基本类型特化的泛型,但是可以静态地生成特化类,从而潜在增加了代码占用空间成本和编译成本。另一种编程语言可以为程序使用的每个实例化生成模板的特化实例化,这可能导致大的静态占用空间。还有第三种语言可以使用模板化的字节码格式,仅执行对运行时的特化,这可能在使用泛型类文件之前需要附加的步骤,从而潜在地损害了运行时性能。



技术实现要素:

特化类的加载或操作可以触发其它类的特化。例如,如果第一类扩展特定的超类,则第一类的特化可以触发该超类的特化。此外,将类特化可以触发作为该类的实现的一部分在内部使用的各个类的特化。

编译器可以识别泛型类之间的依赖性关系,并且依据在第一类被特化时触发其它类的特化的类型变量描述这些类。例如,编译器可以包括在生成类文件时指示类之间的依赖性关系的结构引用。例如,编译器可以依据泛型子类型的类型变量将泛型超类型的描述写出(例如,写到类文件)。因此,第一类的加载可以基于两个类之间的依赖性关系触发第二类的加载。

此外,根据各种实施例,可以存在多级依赖性,并且一个类的特化可以触发多个其它类的特化,多个其它类的特化又可以触发另外一些类的特化。

附图说明

图1是示出根据一个实施例的、实现特化类的依赖性驱动的共同特化的系统的部件的逻辑框图。

图2是示出根据一个实施例的依赖性驱动的共同特化的逻辑框图。

图3是示出如本文所述的用于依赖性驱动的共同特化的方法的一个实施例的流程图。

图4是示出根据一个实施例的、涉及依赖性链当中多个依赖性的依赖性驱动的共同特化的逻辑框图。

图5是示出根据一个示例实施例的、包括多个依赖性的依赖性驱动的共同特化的逻辑框图。

图6是示出根据一个实施例的泛型类的部分特化的逻辑框图。

图7是示出如本文所述的、用于泛型类的部分特化的方法的一个实施例的流程图。

图8是示出根据一个实施例的、具有依赖性驱动的共同特化的部分特化的逻辑框图。

图9是示出根据一个实施例的特化类的手动精炼的逻辑框图。

图10是示出如本文所述的、用于特化类的手动精炼的方法的一个实施例的流程图。

图11是示出根据一个实施例的、用于将新方法添加到特化类的手动精炼的框图。

图12是示出如本文所述的、用于经由特化类的手动精练来添加新方法的方法的一个实施例的流程图。

图13是示出根据一个实施例的、用于泛型类的批量替换的手动精炼的逻辑框图。

图14是示出如本文所述的、用于经由手动精炼对类进行批量替换的方法的一个实施例的流程图。

图15是示出根据一个实施例的、用于泛型方法的手动精炼的逻辑框图。

图16是示出如本文所述的、用于泛型方法的手动精炼的方法的一个实施例的流程图。

图17是示出根据一个实施例的、适于实现特化类的依赖性驱动的共同特化的示例计算机系统的逻辑框图。

具体实施方式

本文描述了对利用独立于平台的面向对象的语言(诸如JavaTM编程语言)进行软件开发的增强的各种实施例,以支持与泛型类型、类和方法的特化相关的各种特征。

例如,特化类的加载或操作可以触发其它类的特化。例如,如果第一类扩展特定的超类,则第一类的特化可以触发该超类的特化。此外,将类特化可以触发作为该类的实现的一部分在内部使用的各个类的特化。根据一个实施例,编译器可被配置为识别泛型类之间的依赖性关系,并且依据基于第一类的特化触发其它类的特化的触发类型(例如,类型和/或类型参数化)的类型变量来描述类。

编译器可以包括在生成类文件时指示类之间的依赖性关系的引用(例如,结构引用)。例如,在一个实施例中,编译器可被配置为依据泛型子类型的类型变量将泛型超类型的描述写出(例如,写到类文件)。因此,在一些实施例中,类文件可以包括指示一个类和另一个类之间的依赖性关系的信息(例如,元数据和/或描述)。加载第一类可以基于依赖性关系而触发第二类的加载。此外,根据各种实施例,可以存在多级依赖性,并且一个类的特化可以触发多个其它类的特化,多个其它类的特化又可以触发另外一些类的特化。

此外,泛型类可以具有多于一个可特化的类型形参并且可以期望特化其中一个或多个类型变量而不特化其它类型变量(例如,使其它类型变量是泛型)。在一些实施例中,部分特化的结果可以是对剩余类型形参进一步可特化的一个或多个另外的泛型类。根据一些实施例,在运行时期间执行的特化器可被配置为部分地特化泛型类(例如,以产生部分特化类),并且随后进一步特化该部分特化类以生成完全特化类。因此,不是一次全部执行泛型类的特化(诸如将Map<K,V>特化成Map<int,int>或Map<long,int>),而是一个类型形参可被部分地特化(诸如产生Map<K,int>),然后在某个稍后时间,剩余的(一个或多个)类型形参可被特化,诸如生成Map<int,int>或Map<long,int>。

虽然运行时特化器可以总是能够生成泛型类的自动特化版本,但是在一些情况下,用户对特化的控制的替代形式可以允许使用自动特化,同时还添加(或重写)特定于特化的方法实现。一般而言,当类被特化时,泛型类的成员集合可能不改变。换句话说,与泛型版本中相同的成员可以存在于自动特化的版本中。但是,特化类的手动精炼可以允许开发人员将特化类的特定(有可能更好)表示和/或实现手动特化。根据各种实施例,替代的以及另外的方法、数据布局、字段等可以在原始泛型类(以及泛型类的自动特化版本)与替换类之间变化。因此,在一些实施例中,可以为泛型类提供类、方法、字段等的替换版本,同时维持相同的接口和表示,而在其它实施例中,可以为泛型类的特定特化提供完全不同的表示(例如,不同的和/或另外的方法、数据布局、字段等)。

例如,泛型类List可以对任何T是泛型并且List的自动特化版本可以包括泛型版本的所有字段和方法,但是如果List对T=int被特化,则特定的一个类方法的新版本也可以包括在特化类中。因此,根据一些实施例,如果List对T=int被特化,则该方法的手动特化版本可以代替自动特化版本被使用。特化类的手动精炼可以包括利用方法的不同版本来重写方法的已有或自动特化版本。此外,手动精炼还可以包括在仅用于特定(并且没有其它)类型参数化的特化类中包括另外的方法。因此,可以在仅当对应的泛型类对特定类型形参被特化时,将精炼方法包括在特化类中。

此外,特化可以包括为泛型类提供替换类。特化类的批量替换可以涉及用替换类替换泛型类的自动特化的能力。根据一些实施例,当类对特定的类型形参被特化时,类的自动特化版本可以完全不被使用并且,代替地,完全不同的手写类可以被使用。在一些实施例中,可以在编译泛型类时使用(和/或需要)类的替代的、手写的特化。但是,在其它实施例中,可以在类被编译之后(例如,在泛型类被特化之前或当时)使用泛型类的替代(例如,替换或精炼)特化。

此外,替换类可以与泛型或自动特化版本具有相同的接口,但是它可以具有完全不同的表示和/或实现。但是,在一些实施例中,替换类必须具有(例如,可以被要求具有)与泛型或自动特化版本相同的接口。例如,根据一些实施例,不具有基类的(以及因此类的自动特化版本的)所有方法(例如,所有非私有方法)的替换类可能导致错误。

在一些实施例中,替换类可以被要求具有(至少)类的泛型或自动特化版本将具有的所有相同方法(例如,使得类的替代版本遵守Liskov代换原理)。每当特定的特化被实例化时,运行时环境可以加载类的替代版本。类的泛型或自动特化版本可以包括识别类的替代版本并指示哪些类型参数化可以触发替代版本的使用的信息。

作为替代,识别类的替代版本并指示哪些类型参数化可以触发替代版本的使用的信息可以存储在除类的泛型或自动特化版本以外的其它地方,诸如在类文件中或信息注册表中,并且因此当使用类的替代版本时运行时可以不必加载类的泛型或自动特化版本。

在以下详细描述中,阐述了众多具体细节,以提供对要求保护的主题的透彻理解。但是,本领域技术人员将理解,要求保护的主题可以在没有这些具体细节的情况下实践。在其它情况下,为了不模糊要求保护的主题,没有在下面详细描述方法、装置或系统,因为它们是本领域普通技术人员已知的。

虽然本文通过对若干实施例和说明性附图的例子描述了各种实施例,但本领域技术人员将认识到,实施例不限于所描述的实施例或附图。应当理解,附图及对其的详细描述不意在将实施例限定到所公开的特定形式,相反,其意在覆盖属于本公开内容的精神和范围内的所有修改、等同物和替代方案。本文中使用的任何标题仅仅是为了组织的目的而不意味着被用来限制描述的范围。如贯穿本申请所使用的,词“可以”是在允许的意义上(即,意味着有可能)而不是在强制的意义上(即,意味着必须)使用的。类似地,词“包括”和“包含”意味着包括但不限于。

以下详细描述的一些部分是依据对存储在特殊装置或专用计算设备或平台的存储器中的二进制数字信号进行操作的算法或符号表示来给出的。在本特定说明书的上下文中,术语特殊装置等包括通用计算机,一旦其被编程为根据来自程序软件的指令执行特定功能。算法描述或符号表示是信号处理或相关领域的普通技术人员用来将他们的工作的实质传达给本领域其他技术人员的技术的例子。算法在这里,并且一般被认为是导致期望结果的操作或相似信号处理的自一致序列。在这种上下文中,操作或处理涉及物理量的物理操纵。通常,但不是必须,这种量可以采取能够被存储、传送、组合、比较或以其它方式被操纵的电或磁信号的形式。有时候,主要是出于共同使用的原因,将这种信号称为位、数据、值、元素、符号、字符、项、数字、数值等被证明是方便的。但是,应当理解,所有这些或相似的术语应当与适当的物理量相关联并且仅仅是方便的标签。除非另有具体说明,如从下面的讨论中显而易见的,否则应当明白,贯穿本说明书,利用诸如“处理”、“计算”、“确定”等术语的讨论是指特殊装置,诸如专用计算机或类似的专用电子计算设备,的动作或过程。因此,在本说明书的上下文中,专用计算机或类似的专用电子计算设备能够操纵或变换通常表示为存储器、寄存器或其它信息存储设备、传输设备或专用计算机或类似专用电子计算设备的显示设备中的物理电子或磁量的信号。

现在转到图1,图1示出了根据各种实施例的、用于编译和执行在高级、独立于平台的面向对象语言中指定的计算机程序的工作流,其中所述语言支持基本和引用数据类型以及如本文所述关于泛型类和/或方法的特化的各种方法、特征和增强。为了说明的目的,以下描述主要在使用JavaTM编程语言的上下文中提供。但是,应当指出的是,所描述的技术可以与在适当的上下文中支持多种类型(诸如基本类型、引用类型、记录类型、联合类型等)及其特化的几乎任何面向对象的编程语言一起使用。

根据所示实施例,当诸如编译器120之类的编译器可以在一个或多个计算设备上实现并且可以接收用于计算机程序的源代码(诸如源代码110)时,工作流可以开始。在各种实施例中,源代码110可以在各种高级和/或独立于平台的面向对象的编程语言(诸如JavaTM和/或其它语言)中指定。例如,在使用JavaTM的实施例中,源代码可以被提供为一组.java文件。在一些实施例中,源代码110可以利用可以包括一种或多种低级和/或中间语言(例如,汇编)的语言的组合来指定。在一些实施例中,源代码中的至少一些可以最初以诸如Python或Ruby之类的动态类型的高级语言来编写,而在其它实施例中,所有源代码可以以诸如JavaTM之类的静态类型的语言来编写。

一般而言,类可以被认为是用户定义的类型或数据结构,其可以包括作为成员的数据、变量、函数、方法和/或其它属性,并且表示用于创建特定类型的编程对象程序的定义、蓝图或模板。类可以为数据成员提供初始值并且为成员函数和方法提供实现。类经常包括在库中。库可以被认为是由软件程序或应用使用的资源的集合。根据一些实施例,库可以包括各种类型的资源中任何一种,包括但不限于数据、文档、类、子例程和/或类型规范。库可以被组织成以便由多于一个应用(有可能在相同的时间)使用,并且可以通过提供资源来促进可重用性,使得应用可以不必实现(或重新实现)相同的行为。

编译器120可以分析源代码110,以产生程序的可执行版本或者字节码文件,诸如所描绘的实施例中的加注释的(一个或多个)类文件130(例如,在JavaTM的情况下是.class文件或.jar文件)。在各种实施例中可以使用不同类型的可执行代码格式;例如,可以使用二进制机器语言代替字节码。在一些场景中,可执行代码(例如,加注释的类文件130)的部分可以是字节码,而其它部分是原生二进制机器语言。

根据一些实施例,作为将程序源代码110编译成可执行代码(例如,加注释的类文件130)的一部分,编译器120可以在生成可执行版本之前执行一系列分析操作并生成各种中间数据结构,诸如应用或实现特化。例如,编译器可以利用泛型类中程序元素的编码(加注释或修饰)形式来应用类型擦除操作,从而创建加注释的类文件130。如上面所指出的,程序元素的编码形式可以包括指示类(或方法)声明的哪些类型变量已被擦除以及哪些类型是类型变量的擦除物的元数据。

在一些实施例中,诸如编译器120之类的编译器可以保留传统上在编译过程期间可能不被保留的某些类型的信息。例如,在一个实施例中,编译器120可以保留作为执行擦除的一部分被使用的信息。编译器可以在加注释的类文件130中包括这种信息(的至少部分)作为关于特化的元数据。

例如,类型擦除操作可以利用泛型类中程序元素的编码(或加注释)形式来应用。程序元素可以表示类签名或声明、方法签名或声明、指令、指令的实参,以及表示、移动或操纵数据的几乎任何程序元素。

程序元素的编码形式可以包括指示类(或方法)声明的哪些类型变量已被擦除以及哪些类型是类型变量的擦除物的元数据。此外,元数据可以包括各种类型的与特化相关的信息。例如,元数据可以指示对类(或方法声明)的类型变量的值进行操作的指令。类似地,元数据可以指示实参指示作为类或方法声明的类型变量的擦除物的类型。

根据一些实施例,加注释的类文件中的元数据可以包括指示哪些类型变量已被擦除以及哪些类型是类型变量的擦除物的特化信息。类型擦除涉及泛型在编程语言(例如,Java语言)中的使用。当执行类型擦除操作时,编译器可被配置为用它们的界限或者如果类型形参无界限的话利用Object类型替换泛型类型中的所有类型形参。所生成的字节码因此可以仅包含普通的类、接口和方法。

此外,结构描述可被用来扩展在运行时环境中描述类的方式。代替仅通过名称来描述类并且使用该名称来定位这个类(例如,在盘上的类文件中),类可以被称为代码生成器函数以及有可能一些实参的组合。换句话说,在一些实施例中,类可以通过指定生成器函数的结构描述以及可能的用于该生成器函数的一个或多个形参来描述。在一些实施例中,结构描述可以被认为是用于其中类名称可被使用的几乎任何情况(例如,实参类型、返回类型、字段类型、超类型、instanceof或cast运算符的操作数等)的类名称(例如,可以代替类名称被使用)。

因此,在一些实施例中,编译器和/或虚拟化的运行时环境可被配置为允许利用结构描述来描述类。例如,可以利用结构描述来描述类之间的依赖性关系(例如,超类/子类关系)。根据一些实施例,类的结构标识可以利用结构描述来使用,诸如以扩展类在运行时环境中被描述的方式。根据一些实施例,类的结构描述可以出现在任何地方,而类名称可以出现在纯粹名义上的VM(例如,未被配置为支持结构描述作为类名称的VM)中。例如,类的结构描述可以作为或代替实参类型、返回类型、字段类型、超类型、instanceof或cast运算符的操作数出现,并且一般而言在类名称可被使用的任何地方。

如图1中所示,加注释的类文件130可以被传递到在执行平台100上执行代码的执行环境,诸如虚拟化的运行时环境140,由此创建各种输出数据和/或行为。根据各种实施例,虚拟化的运行时环境140又可以包括多个不同的部件,诸如存储器管理器160、特化器170、类加载器175、字节码验证器180(例如,以检查可执行代码的有效性),和/或解释器和/或即时(JIT)编译器185。在一些实施例中,JIT编译器可以负责将一些或全部字节码(例如,字节码的被频繁使用的部分)翻译成特定于平台的机器码,以提高程序执行的性能。在一些实施例中,虚拟化的运行时环境140还可以包括实现多个应用编程接口(API)库190的代码。在一些实施例中,虚拟化的运行时环境140可以在诸如操作系统195的较低层软件之上运行。

在不同的实施例中,作为经编译的代码的执行的结果而产生的输出或行为可以包括存储在各级系统存储器中的数据(例如,内存对象和/或数据结构)、存储在持久存储装置上的数据(例如,文件系统上的文件)等。行为还可以包括各种程序功能,诸如在屏幕上显示输出、经网络发送消息,和/或以其它方式与各种用户和/或部件交互。

在一些实施例中,虚拟化的运行时环境140可以使用由编译器120生成的加注释的(一个或多个)类文件130。根据一些实施例,在加载要利用特定参数化特化的类时,虚拟化的运行时环境140可以使用加注释的类文件130作为模板(连同要用于进行特化的形参一起)并且可以产生作为被特化的类的特定特化的新类。例如,当特化类时,一组类型形参可以是用于特化的输入的一部分(例如,List<any T>可以利用T=int作为形参被特化,以获得List<int>)。一般而言,加注释的类文件130可被认为是利用特化相关的元数据标记的类文件。此外,根据各种实施例,加注释的类文件130可以变成作为加注释的类的特化的新类。

特化类的依赖性驱动的共同特化

根据一些实施例,特化类的加载或操作可以触发其它类的特化。例如,如果“class ArrayList<T>extends AbstractList<T>”,则ArrayList<int>的实例化可以要求AbstractList<int>的解析。类似地,给定作为其实现的一部分在内部包括表示映射的节点的类的类Map<keyType,ValueType>,该类的keyType和valueType也将是泛型。利用依赖性驱动的共同特化,根据一些实施例,当泛型类Map<keyType,valueType>被实例化为从int到long的映射(例如,Map<int,long>)时,Map<int,long>的特化实现可以然后触发(一个或多个)依赖类型(诸如上面提到的内部节点类)的特化。

因此,根据一些实施例,诸如编译器120之类的编译器可以识别泛型类之间的依赖性关系并且可以依据触发类型(例如,触发依赖类型的特化的类型)的类型变量来描述依赖类型。例如,当编译器写出类文件而不是名义上写/做一切时,诸如当ArrayList<T>被擦除成只有ArrayList以使得ArrayList扩展List时(如在遗留编译器中所做的那样),被配置为实现依赖性驱动的共同特化的编译器可以包括指示类文件中的依赖性关系的结构引用。

例如,如果ArrayList extends List,而不是仅使用名称List,则编译器可以利用引用例如“通过利用类型形参T对List应用特化变换而产生的类”的结构描述。换句话说,编译器120可被配置为依据泛型子类型的类型变量将泛型超类型的描述写出(例如,写到类文件)。因此,类文件可以包括指示类ArrayList<T>扩展通过对实参(例如,T)应于特化代码生成器而产生的类的描述。加载ArrayList可以触发List的加载并且List可以由结构描述来描述,使得特化器(和/或类加载器)可以应用结构描述来生成用于T的特定参数化的类List并将其加载到运行时高速缓存中。其后,List可以能够用于诸如通过ArrayList来扩展。

根据一个实施例,在超类的结构描述中(例如,在ArrayList<T>extends List<T>的例子中),来自ArrayList的类型变量T出现在超类型的结构描述中,使得,当ArrayList<T>对T=int被特化时,超类型的结构描述中T的出现被int替换。因此,如在ArrayList中声明的T的类型形参给出了“T”在“extends”子句和ArrayList主体中出现的含义。当类被生成时,类ArrayList<int>可以扩展通过应用List对int的特化变换而产生并且可以触发List<int>的加载的类,从而让ArrayList<int>扩展List<int>。

根据一些实施例,当在“<>”之间被声明时,类型形参T引入类型变量T,类似于在方法的“()”之间声明的形式参数引入变量的方式。类型变量T可以在泛型类的签名中(例如,如在“extends”子句中)以及在泛型类的主体中(例如,如在字段的类型中)使用。根据一些实施例,在泛型类的签名中,类型变量T可以出现在类型实参位置(例如“extends AbstractList<T>”),但是不能出现在顶层位置(例如,“extends T”)。但是,在泛型类的主体中,类型变量T可以出现在类型实参位置(例如,作为字段声明,诸如“List<T>f;”)以及在顶层位置(例如,作为字段声明,诸如“Tf;”)。根据一些实施例,每当类型变量T在类型实参位置被使用时,共同特化可以被触发。

在运行时,一个类型(或类)的特化可以触发其它类型的特化。例如,根据一些实施例,如果Foo<T>的实现引用Bar<T>,则Foo的特化可以触发Bar的特化(例如,因为可能需要Bar完成用于Foo的代码的特化)。运行时环境,诸如虚拟化的运行时环境140,可以利用各种类型的信息中的任何一种来识别依赖性关系,诸如通过由编译器使用关于类文件中所包括的依赖类型的信息。

现在转到图2,图2是示出如本文所述的特化类的依赖性驱动的共同特化的一个示例实施例的逻辑框图。如图2中所示,类文件200可以包括具有依赖性关系230的泛型类A 210和泛型类B 220。例如,在一个实施例中,类A可以依赖于类B。根据一些实施例,当依赖性特化器250将类A特化以生成类A 260时,诸如在对特定的类型参数化的类A的实例化时,依赖性特化器250可以确定(例如,识别)类A和类B之间的依赖性关系并且因此还可以将类B特化以生成类B 270。因此,泛型类A 210和泛型类B 220之间的依赖性关系230可以在类A被特化的任何时候触发类B的特化。

从开发人员的角度来看,共同特化简单地基于不同类型(或类)之间的依赖性关系自动发生(例如,无需开发人员的任何特定命令)。

图3是示出如本文所述的用于特化类的依赖性驱动的共同特化的方法的一个实施例的流程图。如方框300中所示,用于实现依赖性驱动的共同特化的方法可以包括在独立于平台的面向对象的运行时环境中特化利用面向对象的编程语言定义的第一泛型类。第一泛型类可以包括一个或多个可特化的类型变量并且这一个或多个类型变量中的每一个可以是经一个或多个类型参数化可特化的。此外,第一泛型类可以对特定的一个类型参数化被特化。

例如,如上所述,在类文件200中定义的泛型类A 210可以对特定的类型参数化被实例化。因此,该泛型类可以对于该特定的类型参数化在虚拟运行时环境140中(例如,在独立于平台的面向对象的运行时环境中)被特化。

根据一个示例实施例,基于Java的类ArrayList<T>可以对类型int被特化。因此,根据示例实施例,泛型类ArrayList可以对T=int在基于Java的虚拟机中被特化。

如方框310中所示,根据一些实施例,可以在第一泛型类和第二泛型类之间确定依赖性关系。例如,运行时环境的特化器(诸如虚拟化的运行时环境140的特化器170和/或依赖性特化器250)可被配置为确定两个类之间的依赖性关系,诸如图2中所示的泛型类A 210和泛型类B 220之间的依赖性关系230。

根据各种实施例,两个类之间的依赖性可以涉及类型或类B在类A中几乎任何类型使用(例如,通过其被创建或触发)。例如,依赖性关系可以涉及超类型、字段描述符、方法描述符的使用,或者另一泛型类型或类在方法主体中的使用(或者通过其被定义/创建)。作为一个例子,类ArrayList<T>可以扩展AbstractList<T>,由此创建(例如,定义)类ArrayList<T>和类AbstractList<T>之间的依赖性关系。

每当泛型类型形参(例如,在上面的例子中由<T>表征的)出现时,依赖性驱动的共同特化可以被触发。因此,根据一些实施例,在泛型类型形参作为超类型、作为转换(cast)的目标、作为方法形参的类型或返回类型出现的任何时候,或者类型形参可以出现的几乎任何地方,依赖性驱动的共同特化可以被触发(例如,特化可以发生)。因此,根据一些实施例,如果特定的泛型类几乎出现在任何地方(例如,在依赖类的API或实现中),则为了能够生成/特化依赖类,特定的泛型类也可以被生成/特化(例如,在依赖类的生成/特化之前、期间或之后)。

如方框320中所示,根据一个实施例,响应于确定依赖性关系,第二泛型类可以基于所确定的依赖性关系对特定的类型参数化被特化。继续上面的例子,ArrayList<T>对特定的类型参数化的特化可以触发AbstractList<T>对相同参数化的特化。根据一些实施例,如果类ArrayList<T>被实例化,并且因此对T=int被特化,则类AbstractList<T>也可以对T=int被特化。

此外,类(或其它类型)之间的相同依赖性关系也可被用来触发对不同参数化的特化。例如,对int特化ArrayList<T>可以触发AbstractList<T>对int的特化。随后,ArrayList<T>可以对long被特化,这可以触发AbstractList<T>对long的特化。换句话说,根据一些实施例,一旦定义了两个泛型类之间的依赖性关系,则每当第一类被特化时,该依赖性关系可以触发依赖类的特化(并且不管多少次)。

虽然上面利用基于超类关系的依赖性进行了描述,但是在其它实施例中,依赖性可以基于类之间的其它关系。例如,如果助手类LinkedListNode<T>嵌套在类LinkedList<T>的主体中,则LinkedList<T>的实例化可以触发LinkedListNode的共同特化。

虽然在上面被描述为按特定次序执行的两个单独且不同的特化,但是根据各种实施例,第一和第二泛型类的特化可以按任何次序发生和/或可以重叠。例如,在一个实施例中,特化器250可以确定第一泛型类和第二泛型类之间的依赖性关系并且,作为响应,可以在特化第一泛型类之前特化第二泛型类。在另一实施例中,特化器250可以开始特化第一泛型类、确定依赖性关系、特化第二泛型类,然后完成第一泛型类的特化。

虽然以上关于图2和图3的例子示出了两个类之间的单个依赖性关系,但是依赖性驱动的共同特化可以涉及多层(甚至许多层)依赖性(或依赖性链)。在一些实施例中,在深度和广度两方面都可以存在许多级的依赖性。例如,图4是示出根据一个实施例的、涉及依赖性链中多个依赖性的依赖性驱动的共同特化的逻辑框图。如图4中所示,类文件可以包括多个泛型类,诸如泛型类A 410、泛型类B 420、泛型类C 440和泛型类D 430。此外,类文件可以定义泛型类之间的依赖性关系。例如,泛型类A 410可以依赖于泛型类B 420和泛型类C 440,如由依赖性关系425和435所示。此外,泛型类B 420本身可以依赖于泛型类D 430,如由依赖性关系435所指示的。

因此,当被配置为实现依赖性驱动的共同特化的运行时环境的特化器(诸如虚拟化的运行时环境140的依赖性特化器450)特化泛型类A 410以生成类A 460时,它可以确定(或识别)泛型类A 410与泛型类B 420和泛型类C 440之间的依赖性关系。响应于确定依赖性关系(例如,当特化泛型类A 410时),依赖特化器450可以特化泛型类B 420和泛型类C 440,以分别生成类B 470和类C 480。

此外,当特化泛型类B 420时,无论是独立地(例如,由于类B的独立实例化)还是响应于泛型类A 410的特化,依赖性特化器450都可以特化泛型类D 430,以生成类D 490。

如上面所指出的,两个类之间的依赖性关系可以基于类之间的各种关系来定义。例如,根据各种实施例,两个类之间的依赖可以存在,因为一个类扩展另一个类、或者因为其实现引用另一个类,或者因为其API将另一个类命名为它的其中一个实参或返回类型。

当第一泛型类被特化时,在一些实施例中,特化器可以基于第一泛型类和任何其它泛型类之间的依赖性关系“跟踪”任何依赖性链并相应地特化其它类。

图5是示出根据一个示例实施例的、包括多个依赖性的依赖性驱动的共同特化的逻辑框图。如图5中所示,类文件可以包括多个类定义,诸如类510、512、514、516和518。类文件中的一个(或多个)类可以依赖于其它类。例如,类510可以依赖于类512、514、516和518。例如,以下示例代码示出了依赖于其它类的类510的可能定义:

因此,类SortedList依赖于多个其它类,诸如List、Comparator、Collection和Set。具体而言,List是SortedList的超类,Comparator在字段签名中作为SortedList的形参被命名,Collection在方法签名中被命名,并且类Set在方法的主体内被使用。因此,SortedList基于不同类型的依赖性关系依赖于每个其它类。

当将类510特化以生成类530时,根据一个示例实施例,依赖性特化器520可以确定类SortedList依赖于其它类并且,作为响应,可以将类512、514、516和518分别特化以生成类532、534、536和538。具体而言,根据一个实施例,特化SortedList<int>可以触发List<int>(超类)、Comparator<int>(字段签名)、Collection<int>(方法签名)、Set<int>(方法主体)的特化。

此外,特化的定时可以从实施例到实施例有所变化,诸如依赖于不同运行时环境之间的差异。例如,在一个实施例中,可以直到方法countUnique在程序执行期间真正被调用,Set<int>才被特化。

虽然上面的例子使用公有类型,但是依赖性驱动的共同特化不限于公有类型。例如,以下样本代码示出了具有非公有类型的依赖性驱动的共同特化:

根据一些实施例,在上面的例子中,虽然类Node对于LinkedList是私有的,但是每当LinkedList被特化时,它可以被特化。

此外,作为特化单个依赖类的一部分,相同的泛型类可以对不同的类型形参被特化多次。作为一个非常简单的例子,接口Map<K,V>可以利用两个不同的ArrayList来实现,一个用于键,一个用于值,如以下示例代码中所示:

在上面的例子中,ArrayList基于K和V的各个类型形参被共同特化。

特化类的部分特化

泛型类可以具有多于一个可特化的类型形参,诸如在例子中是Map<K,V>。可能期望特化其中一个或多个类型变量,而不特化其它类型变量(例如,保留其它类型变量是泛型)。图6是示出根据一个实施例的泛型类的部分特化的逻辑框图。根据一些实施例(特化器,诸如虚拟化的运行时环境140的部分特化器620)可被配置为部分地特化泛型类610,以产生部分特化的类630,并且还可被配置为随后进一步特化部分特化类630,以生成完全特化类640。

例如,泛型类610可以表示泛型类Map<K,V>并且部分特化器620可被配置为将泛型类610特化成具有泛型键但对于值具有int值的映射,诸如Map<K,int>。作为替代,泛型类Map<K,V>可被特化成对于键具有int值但具有泛型值的映射,诸如在Map<int,V>中。这在本文中可以被称为“部分特化”。

在一些实施例中,部分特化的结果可以是对剩余的类型形参进一步可特化的一个或多个另外的泛型类。例如,部分特化类630可以表示Map<K,int>并且可以进一步特化以生成完全特化类640,完全特化类640可以表示对键具有特定类型的一个或多个映射,诸如Map<int,int>或Map<long,int>。换句话说,对于具有多于一个类型变量的泛型类型(例如,Map<K,V>),其中一个类型变量可被特化(例如,Map<int,V>),而不特化其它(一个或多个)类型变量。结果所得的类可以被认为是可进一步被特化的部分特化类。

因此,不是一次全部执行泛型类的特化(诸如通过将Map<K,V>特化成Map<int,int>或Map<long,int>),而是一个类型形参可被部分特化,诸如产生Map<K,int>,然后在某个稍后时间,剩余的(一个或多个)类型形参可被特化,诸如生成Map<int,int>或Map<long,int>。

虽然在图6中被示为将部分特化类630存储回类文件200,但是在一些实施例中,部分特化类630可以存储在不同位置,诸如在单独的类文件中或者在虚拟化的运行时环境140中的存储器中等。

图7是示出如本文所述的用于泛型类的部分特化的方法的一个实施例的流程图。如方框700中所示,泛型类可以被部分特化。根据一个实施例,泛型类可以包括多个可特化的类型变量,其中每个类型变量可以经多个类型参数化是可特化的。

如方框710和720中所示,将泛型类部分特化可以涉及经多个类型参数化中特定的一个类型参数化对多个类型变量中特定的一个类型变量将泛型类特化,如方框710中所示,并且不对另一个可特化类型变量将泛型类特化,如方框720中所示,使得部分特化类可对多个类型参数化中每一个对多个可特化类型变量中至少另一个可特化类型变量进一步可特化。例如,

interface Map<any K,any V>{...}

可以对一个类型变量(诸如K)被部分特化,而不特化另一个类型变量。例如,在以下例子中,

class IntBasedMap<any V>implements Map<int,V>{...}

IntBasedMap可以是Map的部分特化。仅Map的一个类型变量(例如,K)被特化,因此允许IntBasedMap(例如,部分特化的Map<int,V>)经Map可特化的任何或全部类型参数化对V被进一步特化。在一些实施例中,部分特化类可以经该类可特化的多个可能的类型参数化当中每一个类型参数化进一步可特化。因此,根据各种实施例,在如上面的例子中那样对K=int被部分特化之后,部分特化的Map(例如,作为IntBasedMap)可以经其它类型参数化针对V进一步特化,诸如对V=long、V=boolean、V=String等。此外,如上面的例子中所示,部分特化类(诸如Map<int,V>)可以看起来像参数化的类型(例如,在“extends”子句中)。在一些实施例中,参数化的类型(例如,Map<int,V>)可被识别为泛型类(例如,Map<K,V>)的部分参数化,并且泛型类可被部分特化以形成另一泛型类(例如,Map<int,V>),从而允许形成参数化的类型。形成参数化的类型常常可以意味着通过将类型实参绑定到类型形参K和V来“实例化”泛型类Map<K,V>,但是在一些实施例中,恒等函数可被应用到部分特化的泛型类Map<K,V>,以形成参数化的类型,类似于类型String是应用到非泛型类String的恒等函数的方式。

如方框730中所示,根据一些实施例,然后,部分特化类可以随后对另一个可特化的类型变量被进一步特化,使得部分特化类变得完全特化。继续上面的例子,部分特化的Map<int,V>(例如,作为IntBasedMap)可以对剩余的类型变量(例如,V)进一步被特化,如在下面的示例代码中:

class IntToIntMap extends IntBasedMap<int>{...}

因此,根据一个示例实施例,Map<int,V>可以对V=int(作为一个例子)被进一步特化,得到Map<int,int>(例如,经由IntBasedMap和IntToIntMap)。此外,经一个类型参数化被进一步特化之后,相同的部分特化类可以经其它的类型参数化被进一步特化。例如,相同的部分特化的Map类可以对V=long被进一步特化,如在以下的示例代码中:

class IntToLongMap extends IntBasedMap<long>{...}

在一些实施例中,类的部分特化可以通过以下来实现:部分特化注入到类中的元数据(例如,为了使类可特化),然后将部分特化的元数据传播到新的、部分特化的类文件中,使得部分特化的结果可重新特化。因此,根据一些实施例,部分特化可以通过将特化元数据的投影从原始类正向传播到部分特化的结果中来实现。

这可以通过开发人员编写他的代码的方式——他想要具有不同级别的部分特化的方式——来实现。如本文所述,将泛型类特化可以有两个不同的原因。首先,将泛型类特化会导致更好的性能(例如,对int的操作比对对象的操作更快),其次,泛型类可以被特化,以利用关于实参的特定信息(例如,诸如添加仅适用于某些类型形参的新功能)。

因此,即使你不知道关于值的任何内容(例如,Map<int,V>),具有其中键是int的Map也是有益的。然后,这个部分特化的Map类可被特化,以使用特定的映射值,而不必特化整个类(例如,因为Map<K,V>已被部分特化成Map<int,V>)。

因此,根据一些实施例,类的部分特化可以涉及类的特化,以产生进一步可特化的类。例如,下面是HashMap的部分特化:

class IntMap<K>extends HashMap<K,int>

HashMap的部分特化需要将元数据(如上所述)传播到所生成的类中,使得类型变量K可被进一步特化,并且允许将该进一步特化的结果识别为HashMap<K',int>的子类型。

在一些实施例中,部分特化类可被显式地声明,诸如在以下示例代码中:

class HashMap<int,V>implements Map<int,V>

作为替代,可以自动生成(例如,由运行时环境)多个不同的部分特化(例如,Map<int,V>、Map<long,V>等),每当特定类型的使用发生时,其本身根据需要是可特化的。因此,可以存在多个不同的部分特化并且它们可以出现在类文件中基于可特化的泛型类的参数化的类型可能出现的任何地方(例如,超类型、局部变量、字段类型、方法形参的类型、类型转换等)。

此外,部分特化可以与上述依赖性驱动的共同特化相结合。图8是示出根据一个实施例的、具有依赖性驱动的共同特化的部分特化的逻辑框图。泛型类810可以包括多个泛型类型变量并且可以由虚拟化的运行时环境140的特化器850部分特化,以生成部分特化类820。此外,泛型类810可以依赖于泛型类840,如由依赖性关系830所指示的。如上面所指出的,依赖性关系可以涉及超类型、字段描述符、方法描述符、或者另一泛型类型或类在方法主体中的使用(或者通过其定义/创建)。例如,泛型类810可以表示泛型类Map<K,V>,它可以利用被表示为泛型类840的泛型MapNode类作为其实现的一部分,如在以下的示例代码中:

当特化器870部分地特化泛型类810以生成部分特化类820时,特化器870可以确定或识别泛型类810和泛型类840之间的依赖性关系,并且因此可以(部分地)特化泛型类840,从而生成部分特化类860。例如,对K=int部分特化Map<K,V>可以触发MapNode<K,V>对K=int的部分特化,如以下示例代码中所示:

随后,根据一个实施例,部分特化类820可被进一步特化,以生成完全特化类880,这还可以触发部分特化类860的进一步特化,以生成完全特化类890。例如,部分特化的Map<int,V>可以对V=int被进一步特化,从而触发MapNode(int,V)对V=int的进一步特化,如以下示例代码中所示:

作为另一个例子,泛型类HashMap<K,V>可以扩展Map<K,V>。根据一些实施例,诸如对K=int部分特化HashMap,可以触发Map对K=int的(部分)特化。

作为又一个例子,Map<K,V>的方法可以采用从V到U的映射函数,并返回Map<K,U>(其映射可以对原始映射中的所有(k,v)都是(k,mapper(v)))。当Map被部分特化时,映射器函数的特化可以基于映射类和映射器函数之间的依赖性关系被触发,如下面的示例代码中所示:

特化类的手动精炼

虽然运行时特化器可以总是能够生成泛型类的自动特化版本,但是在一些实施例中,对特化的用户控制的替代形式可以涉及使用自动特化同时还添加(或重写)特定于特化的方法实现。一般而言,根据一些实施例,泛型类的成员集合在其被特化时不改变——在自动特化版本中存在与泛型版本中相同的成员。但是,特化类的手动精炼可以允许开发人员手动特化特化类的一个或多个方法的更好表示和/或实现。

换句话说,泛型类List对任何T可以是泛型,并且List的自动特化版本可以包括泛型版本的所有字段和方法,但是如果List对T=int被特化,则特定方法的新版本可以被包括。因此,根据一些实施例,List对T=int被特化,该方法的手动特化版本可以代替自动特化版本被使用。

作为另一个例子,用于特定类型参数化的方法可以被添加到ArrayList,如下所示:

在一些实施例中,某些方法对泛型类的一些实例化可能是有意义的,但对于其它实例化没有意义。例如,如果T是int或long,但不是Shoe或某个其它对象,则List<T>上的sum()方法可能有意义。一些实施例可以包括关于给定实例化的条件成员的声明-地点机制。这也可以包括如果它们都出现则可能彼此不一致的成员,诸如对于List<int>的int承载sum()方法和对于List<double>的double承载sum()方法。此外,一些实施例可以包括类文件表示,当类被实例化为已擦除类时,即,没有任何类型参数化,该类文件表示允许忽略某些成员。

特化类的手动精炼,以重写功能

根据一些实施例,特化类的手动精炼替换(重写)否则将由特化器生成的功能。以类似于如上所述的自动特化类的批量替换的方式,方法也可以被(手动地)添加以替换功能,诸如重写自动特化的成员。

对于泛型类的一些实例化,替换自动特化的版本会是优选的。一些实施例可以包括以下机制(诸如语言机制):通过该机制,单个类文件可以既描述类成员的泛型版本,又在一个或多个特定于实例化的层中“重写”该泛型版本。于是,类既可以包括方法的泛型版本,又可以包括用于特定类型特化的方法的替代版本。

图9是示出根据一个实施例的特化类的手动精炼的逻辑框图。如图9中所示,类文件200可以包括类A 900,类A 900包括当类A 900被特化时可被自动特化的已有方法910。此外,类A 900还可以包括当类A 900对特定类型形参被特化时代替已有方法920被使用的精炼方法920。当类A 900被特化时,精炼特化器930可被配置为确定该类正在对其被特化的特定的类型参数化是否是应当使用该精炼方法的类型参数化。换句话说,特化器可以确定精炼方法与类正在对其被特化的特定的类型参数化对应。如果精炼特化器930确定应应当使用精炼方法920,则精炼特化器930可以加载并特化包括该精炼方法的类,如由类A 940和精炼方法950所示。作为替代,如果类正在对该精炼方法不应当被使用的不同类型参数化被特化,则精炼特化器930可以利用已有方法910的自动特化版本来加载和特化该类,如由类A 960和自动特化方法970所示。

因此,根据一些实施例,通过对特定类型参数化重写特定方法(或添加新方法),用户控制的替代形式可被用来增强特化。因此,开发人员可以能够对一些类型利用最佳可能的实现,同时对其它类型依赖于通用(例如,自动特化的)版本。例如,List<int>可以具有sum()方法,或者已有方法的优化版本可以对特定类型参数化被手动编写。泛型类的用户不必知道关于手动精炼的任何内容。例如,泛型类的用户不必为了利用手动精炼或重写版本而请求或指定使用手动精炼或重写版本。相反,根据一些实施例,仅仅对特定类型形参实例化类就可以触发手动精炼的使用(例如,如由泛型类的开发者提供的),而无需用户对泛型类的任何特定知识或请求。

在一个实施例中,泛型类的开发者可以写(例如,重写的方法的)多个版本并且编译器可被配置为将该代码编译成类文件中的多个版本。类文件还可以包括指示对哪些类型特化使用哪些版本的信息。此外,运行时环境可被配置为使用类文件中的信息来确定在加载特定特化时要使用哪个版本。

作为另一个例子,类Box可以保存值,如以下示例代码中所示:

在上面的例子中,方法toString可以对所有类型T起作用,但是可能是为了给出更好的答案,或者是由于更快的实现,toString()的更特化的版本可以提供T=int的Box的实例化。此外,在一些实施例中,附加的类型约束(T=int)可以在toString()的特化版本的主体中使用,以便对主体进行类型检查,诸如以便确保编译器知道“t”的类型实际上是“int”而不是泛型“T”。

根据一些实施例,当重写特化的泛型类的特定方法时,该方法的替代版本可以被包括在类文件中并且可以被指示为应用到特化的特定集合(例如,对于某些类型形参)。在一些实施例中,当泛型类的方法在运行时被特化时,如果使用与方法的替代版本对应的其中一个特定的特化,则可以使用该方法的替代版本(例如,拷贝到特化类)而不是自动特化版本。

在一些实施例中,精炼方法可被用于多个类型参数化。例如,精炼方法可以特定于short和char,如以下例子中所示:

<where T extends Serializable>void writeObject(){...}

//仅对于short和char

<where T has 16bits>void swapBytes(){...}

图10是示出如本文所述的、用于特化类的手动精炼的方法的一个实施例的流程图。如方框1000中所示,泛型类可以对特定的类型参数化被特化。例如,在运行时,可以加载包括对于经多个类型参数化可特化的泛型类的类声明的类文件。类声明可以包括特定于多个类型参数化中特定的一个的精炼方法,并且,当类对该特定的类型参数化被特化时,可以为泛型类的方法提供替代实现。

例如,特化器可被配置为加载Box类并对T=int特化Box类。如方框1010中所示,特化器可以确定对泛型类匹配已有方法并且与特定的类型参数化对应的精炼方法。例如,特化器可以确定精炼toString方法对于重写泛型toString方法并与类型参数化T=int对应的Box类存在。

如方框1020中所示,根据一个实施例,响应于确定精炼方法与特定的类型参数化对应,特化器可以在泛型类的特化版本中包括精炼方法,而不是包括已有方法的自动特化版本。换句话说,当对特定的类型参数化特化泛型类时,特化器可被配置为在基于特定的类型参数化的特化类中包括精炼方法。例如,特化器可以在Box类的特化版本中包括精炼toString方法,而不是包括toString方法的泛型或自动特化版本。因此,当该类对特定的类型参数化被特化时,精炼方法可以为泛型类的方法提供替代实现。

此外,如方框1030中所示,泛型类可以对不同的类型参数化被特化,并且,如方框1040中所示,特化器可以确定精炼方法不与该不同的类型参数化对应。例如,来自以上例子的Box类可以对除T=int之外的类型参数化被特化,并且因此特化器可以确定精炼toString方法不与该类型参数化对应。作为响应,特化器可以不在对于其它类型参数化的特化中包括该精炼方法,如方框1050中所示。例如,当对除T=int之外的另一类型参数化特化Box类时,特化器可以不在该类的特化版本中包括精炼toString方法(例如,与T=int对应的toString方法),而是可以包括toString方法的自动特化版本。作为替代,根据一个实施例,对于其它类型参数化可以存在另一精炼stostring方法(例如,在类声明中),并且因此,当该类对其它类型参数化被特化时,可以包括在特化类中。

当开发人员具有关于类型的特定知识时,可以存在比自动版本更好的(例如,更小、更快、更高效的)实现。例如,如果程序使用参数化的类型ArrayList<boolean>,则ArrayList<T>类的自动特化版本可以利用大于存储布尔值所需的最小值的缺省元素规模。例如,在Java编程语言中,缺省地,布尔可以利用8位(或更大)位置存储。因此,在一些实施例中,当ArrayList<T>对T=Boolean被特化时,开发人员能够提供其自己的使用不同存储机制的实现(例如,使用long的内部数组并执行逐位计算)。

因此,可以存在泛型ArrayList<T>,但是,如果其对T=Boolean被实例化,则可以使用不同的手写类来代替自动特化版本。在一些实施例中,自动特化版本和手写版本可以被要求具有相同的签名,但是可以具有完全不同的表示和/或完全不同的成员,等等。

此外,泛型类的自动特化版本可以仅被用不同特化的不同方法来部分地重写。因此,不是替换整个类和/或实现,而是仅存在于特定实例化中的个体方法可以被替换(例如,以使用更好的实现)或者个体方法可以被添加(如上面所指出的)。因此,根据一些实施例,开发人员可以提供手写的精炼,其提供类、个体替换(例如,重写)方法和/或另外的方法的全新表示。

例如,虽然List<int>可以具有add和get的自动特化实现,但是对于某些类型参数化(例如,T=int)包括sum方法会是有益的,该sum方法可以不是List的所有特化版本的成员(例如,对于T的所有类型参数化)。

例如:

手动精炼,以提供新的方法

在一些实施例中,编译器和/或运行时可以允许的方法对于类的某些(例如,一个,一些或全部)特化版本被手动添加到类,诸如向特化类添加不在自动特化版本中存在的新功能。

图11是示出根据一个实施例的、用于将新方法添加到特化类的手动精炼的框图。如图11中所示,类文件可以包括类A 1100,其既包括(一个或多个)已有方法1110又包括仅与特定的类型参数化对应的新方法1120。当类A 1100对新方法1120对应的类型参数化被特化时,精炼特化器1130可以包括新方法,以及类的特化版本中(一个或多个)已有方法的特化版本,如由类A 1140中的新方法1150和(一个或多个)已有方法1160所示。

但是,当类对新方法不对应的类型参数化被特化时,特化器可以不在特化类中包括该新方法,而是代替地可以仅包括(一个或多个)已有方法的特化版本,如由包括(一个或多个)已有方法1180但不包括新方法的特化版本的类A 1170所示。

因此,不是简单地基于类型变量的实例化替换方法的主体,而是可以添加新方法。根据一些实施例,新方法可以被称为“有条件”方法,因为它可以只被包括在某些类型特化中。

作为另一个例子:

在上面的例子中,两个有条件sum()方法被添加到List。其中一个Sum()方法是实例化List<int>的成员,而另一个是实例化List<long>的成员,同时任何一个都不是List<?>或泛型List<T>的成员。

图12是示出如本文所述、用于经由特化类的手动精炼来添加新方法的方法的一个实施例的流程图。如方框1200中所示,泛型类可以对特定的类型参数化被特化。例如,特化器可被配置为加载类并对特定的类型参数化将类特化。利用上面的例子,特化器可被配置为加载List类并对T=int特化List类。如方框1210中所示,特化器可以确定用于泛型类的、与特定的类型参数化对应的新方法。例如,特化器可以确定,对于Box类,存在与类型参数化T=int对应的新sum()方法。

如方框1220中所示,根据一个实施例,响应于确定新方法与特定的类型参数化对应,特化器可以在泛型类的特化版本中包括该新方法,以及包括任何已有方法的自动特化版本。例如,特化器可以在List类的特化版本中包括sum()方法,以及包括add()和get()方法的泛型或自动特化版本。

此外,如方框1230中所示,泛型类可以对另一类型参数化被特化,并且,如方框1240中所示,特化器可以确定新方法不与该另一类型参数化对应。例如,来自上面的例子的List类可以对除T=int之外的类型参数化被特化,并且因此特化器可以确定新的sum()方法不与该类型参数化对应。作为响应,特化器可以不在用于该另一类型参数化的特化中包括该新方法,如方框1250中所示。例如,当对除T=int之外的类型参数化特化List类时,特化器可以不在该类的特化版本中包括sum()方法(例如,与T=int对应的方法),但可以仅包括add()和get()方法的自动特化版本。

在一些实施例中,精炼方法可被用于多于一个类型参数化。例如,泛型类可以包括用于T=Object的精炼方法。在一些实施例中,如果泛型类对T=String(即,String是对象)被特化,则用于T=Object的精炼方法可被包括在泛型类的特化版本中。但是,在其它实施例中,如果相同的泛型类对T=String被特化,则精炼方法(例如,对于T=Object)不能包括在特化版本中。因此,在一些实施例中,只有当泛型类对为其指定特定精炼方法的确切类型参数化被特化时,才可以使用该特定精炼方法,而在其它实施例中,精炼方法可以用于多个类型参数化。

特化类的批量替换

此外,在一些实施例中,可以既不使用泛型类的自动特化也不使用该类的手动精炼,而是代替地可以使用全新的、手写的类。一般而言,替换类可以具有与泛型或自动特化版本相同的接口,但是它可以具有完全不同的表示和/或实现。因此,根据一些实施例,替换类可以被要求具有(至少)类的泛型或自动特化版本将具有的所有相同的方法(例如,使得类的替代版本遵守Liskov代换原理)。在运行时,每当特定特化被实例化时,运行时环境可以加载类的替代版本。

图13是示出根据一个实施例的、用于泛型类的批量替换的手动精炼的逻辑框图。如图13中所示,类文件200可以包括泛型类1300以及替换类1310。替换类1310可以与特定的类型参数化对应并且可以预期在泛型类1300对这些特定的类型参数化被特化时替换泛型类1300。例如,当泛型类1300对替换类1310对应的类型参数化A 1350被特化时,精炼特化器1320可以加载特化的替换类1330而不是泛型类1300的自动特化版本。作为替代,当泛型类1300对替换类1310不对应的不同类型参数化(诸如类型参数化B 1360)被特化时,特化器可以加载并特化泛型类1300,如由自动特化类1340所表示的。

在一个实施例中,类的泛型或自动特化版本可以包括识别类的替代版本并指示哪些类型参数化可以触发替代版本的使用的信息。但是,在其它实施例中,识别类的替代版本并指示哪些类型参数化可以触发替代版本的使用的信息可以存储在除类的泛型或自动特化版本以外的其它地方(例如,在类文件中或信息注册表中),并且因此运行时可以不必在使用类的替代版本时加载类的泛型或自动特化版本。

例如,可以提供用于泛型类的给定实例化的替换定制表示,如在以下例子中:

类似地,我们可能具有其键和值为int的散列表的特化表示:

根据一些实施例,当实现类的批量替换时,运行时类加载器和/或特化器可被配置为确定替换类应当被使用(例如,基于被实例化的特定类型形参)并定位和加载替换类来代替泛型类的自动特化和/或手动精炼版本。

图14是示出如本文所述的、用于经由手动精炼来批量替换类的方法的一个实施例的流程图。如方框1400中所示,泛型类可以对特定的类型参数化被特化。例如,利用上面的示例,特化器可被配置为加载ArrayList类并对T=Boolean特化ArrayList类。根据一些实施例,ArrayList类可以是基于泛型类声明并且可以经多个类型参数化可特化的泛型类。如方框1410中所示,特化器可以确定与特定的类型参数化对应的泛型类的替换(例如,精炼)类。例如,特化器可以确定ArrayList类的精炼版本存在并且与类型参数化T=boolean对应。在一个实施例中,用于ArrayList的类文件可以包括用于ArrayList的精炼类声明,其为泛型ArrayList提供(例如包括)当泛型类对特定的类型参数化(例如,T=boolean)被特化时使用的替代实现。

如方框1420中所示,根据一个实施例,响应于确定替换类与特定的类型参数化对应,特化器可以加载替换类而不是加载泛型类的自动特化版本。例如,特化器可以加载ArrayList的ArrayList<boolean>版本,而不是ArrayList的自动特化版本。

因此,在一个实施例中,将泛型类特化可以包括加载与泛型类的精炼类声明对应(例如,基于泛型类的精炼类声明)的类,该精炼类声明特定于特定的类型参数化并且当泛型类对特定的类型参数化被特化时为泛型类提供替代实现。此外,泛型类可以对其它类型参数化可特化,而无需加载与精炼类声明对应的类。

例如,如方框1430中所示,泛型类可以对另一类型参数化被特化,并且,如方框1440中所示,特化器可以确定替换类不与该另一类型参数化对应。例如,来自上面例子的ArrayList类可以对除T=boolean以外的类型参数化被特化,并且因此特化器可以确定替换类(例如,ArrayList<boolean>)不与该另一类型参数化对应。作为响应,根据一个实施例,特化器可以不加载ArrayList的ArrayList<boolean>版本,而是可以加载ArrayList的自动特化版本,如方框1450中所示。

如上面关于方法的手动精炼所描述的,在一些实施例中,精炼类声明可被用于多于一个类型参数化。例如,泛型类可以具有用于T=Object的精炼泛型类声明。在一些实施例中,如果泛型类对T=String(即,String是对象)被特化,则用于T=Object的精炼类声明可被用于泛型类的特化版本。但是,在其它实施例中,如果相同的泛型类对T=String被特化,则精炼类声明(例如,对于T=Object)可以不被用于该类的特化版本。因此,在一些实施例中,只有当泛型类对为其指定特定精炼类声明的确切类型参数化被特化时,特定精炼类声明才可被使用,而在其它实施例中,精炼方法可用于多个类型参数化。

在一些实施例中,特化的泛型类的手动精炼也可以与泛型类的部分特化和依赖性驱动的共同特化相结合,如上所述。例如,部分特化类可被手动精炼,以包括用于一个或多个特化的一些附加功能,并且部分特化还可以触发一个或多个其它泛型类的(完全或部分)特化。

泛型方法的手动精炼

除了基于类类型形参的特定实例化来使用手动精炼,如上所述,手动精炼也可以基于泛型方法的方法类型形参来提供。在一些实施例中,当类中的泛型方法(例如,类自身不必是泛型)对特定类型被特化时,该方法的替代版本可被使用。

例如,假设我们有:

class IntList extends List<int>{...}

并且我们有泛型方法:

我们可以特化T=int实例化:

在这里,我们说这是已有泛型方法对类型形参的特定组合的特化。当开发人员写该方法的不同版本时,不同的版本可以由编译器传播到类文件中,并且,在运行时,该方法的特定版本基于被特化的特定类型形参被加载。

图15是示出根据一个实施例的、用于泛型方法的手动精炼的逻辑框图。如图15中所示,类文件200可以包括泛型方法1500以及替换方法1510。替换方法1510可以与特定的类型参数化对应并且可以预期在泛型方法1500对这些特定的类型参数化被特化时替换泛型方法1500。例如,当泛型方法1500对替换方法1510对应的类型参数化A 1550被特化时,精炼特化器1520可以加载特化的替换方法1530而不是泛型方法1500的自动特化版本。作为替代,当泛型方法1500对替换方法1310不对应的不同类型参数化(诸如类型参数化B 1560)被特化时,特化器可以加载并特化泛型方法1500,如由自动特化方法1540所表示的。

图16是示出如本文所述的、用于泛型方法的手动精炼的方法的一个实施例的流程图。如方框1600中所示,泛型方法可以对特定的类型参数化被特化。例如,特化器可被配置为加载并对特定的类型参数化将方法特化。利用上面的例子,特化器可被配置为加载singletonList方法并对T=int特化singletonList方法。如方框1610中所示,特化器可以为泛型方法确定与特定的类型参数化对应的替换方法。例如,特化器可以确定singletonList方法的替换版本存在并且与类型参数化T=int对应。

如方框1620中所示,根据一个实施例,响应于确定替换方法与特定的类型参数化对应,特化器可以加载替换方法,而不是加载泛型方法的自动特化版本。例如,特化器可以加载singletonList方法的specialization<T=int>版本,而不是singletonList的自动特化版本。

此外,如方框1630中所示,泛型方法可以对另一类型参数化被特化,并且,如方框1640中所示,特化器可以确定替换方法不与该另一类型参数化对应。例如,来自上面的例子的singletonList方法可以对除T=int之外的类型参数化被特化,并且因此特化器可以确定替换方法(例如,specialization<T=int>版本)不与该另一类型参数化对应。作为响应,根据一个实施例,特化器可以不加载singletonList方法的specialization<T=int>版本,而是可以加载singletonList方法的自动特化版本,如方框1650中所示。

在至少一些实施例中,实现本文描述的一种或多种技术的一部分或全部的计算机系统可以包括通用计算机系统,该通用计算机系统包括或被配置为访问一个或多个计算机可读介质。图17示出了适于实现本文所述的方法、特征和增强的此类通用计算设备3000。在所示实施例中,计算设备3000包括经由输入/输出(I/O)接口3030耦合到系统存储器3020的一个或多个处理器3010。计算设备3000还包括耦合到I/O接口3030的网络接口3040。

在各种实施例中,计算设备3000可以是包括一个处理器3010的单处理器系统或包括若干处理器3010(例如,两个、四个、八个或另一合适数目)的多处理器系统。处理器3010可以包括能够执行指令的任何合适的处理器。例如,在各种实施例中,处理器3010可以是实现各种指令集体系架构(ISA),诸如x86、PowerPC、SPARC或MIPS ISA或任何其它合适的ISA,当中任何一个的通用或嵌入式处理器。在多处理器系统中,每个处理器3010通常可以,但不必,实现相同的ISA。

系统存储器3020可被配置为存储可由(一个或多个)处理器3010访问的程序指令和数据。在各种实施例中,系统存储器3020可以利用任何合适的存储器技术来实现,诸如静态随机存取存储器(SRAM)、同步动态RAM(SDRAM)、非易失性/闪存型存储器或任何其它类型的存储器。在所示实施例中,实现一个或多个期望功能的程序指令和数据,诸如上述那些方法、技术和数据,被示为作为代码(即,程序指令)3025和数据3026存储在系统存储器3020中。例如,在一个实施例中,存储器3020以及代码3025和数据3026可以存储用于实现上述编译器120和/或虚拟化运行时环境140的程序指令和数据。

在各种实施例中,编译器120和/或虚拟化的运行时环境140(和/或其任何个别的子模块)可以各自以各种编程语言或方法中任何一种来实现。例如,在一个实施例中,编译器120和/或虚拟化的运行时环境140可以用C、C++、汇编,JAVA或其它通用编程语言中任何一种来编写,而在另一实施例中,它们当中一个或多个可以用不同的、更专门的编程语言来编写。而且,在一些实施例中,编译器120和/或虚拟化的运行时环境140(和/或其各个子模块)不能用相同的编程语言来实现。

在一个实施例中,I/O接口3030可被配置为协调设备中处理器3010、系统存储器3020和任何外围设备,包括网络接口3040或其它外围接口,之间的I/O流量。在一些实施例中,I/O接口3030可以执行任何必要的协议、定时或其它数据变换,以便将来自一个部件(例如,系统存储器3020)的数据信号转换成适于被另一部件(例如,处理器3010)使用的格式。在一些实施例中,I/O接口3030可以包括对通过各种类型的外围总线,诸如像外围组件互连(PCI)总线标准或通用串行总线(USB)标准的变型,附连的设备的支持。而且,在一些实施例中,I/O接口3030,诸如到系统存储器3020的接口,的一些或全部功能可以直接被结合到处理器3010中。

网络接口3040可被配置为允许在计算设备3000和附连到一个或多个网络3050的其它设备3060之间交换数据。在各种实施例中,网络接口3040可以支持经由任何合适的有线或无线通用数据网络的通信,诸如像以太网类型。

在一些实施例中,系统存储器3020可以是被配置为如上文关于图1-6所述存储用于实现对应方法和装置的实施例的程序指令和数据的计算机可读(例如,计算机可访问)介质的一个实施例。但是,在其它实施例中,程序指令和/或数据可以在不同类型的计算机可读介质上被接收、发送或存储。一般而言,计算机可读介质可以包括非暂态存储介质或存储器介质,诸如磁性或光学介质,例如,经由I/O接口3030耦合到计算设备3000的盘或DVD/CD。非暂态计算机可读存储介质还可以包括可作为系统存储器3020或另一类型存储器包括在计算设备3000的一些实施例中的任何易失性或非易失性介质,诸如RAM(例如,SDRAM、DDR SDRAM、RDRAM、SRAM等)、ROM等。

另外,计算机可读介质可以包括传输介质或信号,诸如经由诸如网络和/或无线链路的通信介质传送的电、电磁或数字信号,其中通信介质诸如可以经由网络接口3040实现。诸如图17中所示的多个计算设备的部分或全部可被用来实现在各种实施例中所描述的功能;例如,在各种不同的设备和服务器上运行的软件部件可以协作,以提供功能。在一些实施例中,除了或代替利用通用计算机系统实现,所描述的功能的一部分还可以利用存储设备、网络设备或专用计算机系统来实现。如本文所使用的,术语“计算设备”是指至少所有这些类型的设备,并且不限于这些类型的设备。

各种实施例还可以包括在计算机可读介质上接收、发送或存储根据前面的描述实现的指令和/或数据。一般而言,计算机可读介质可以包括存储介质或存储器介质,诸如磁性或光学介质,例如盘或DVD/CD-ROM,易失性或非易失性介质,诸如RAM(例如,SDRAM、DDR、RDRAM、SRAM等等)、ROM等。在一些实施例中,计算机可读介质还可以包括经由诸如网络和/或无线链路的通信介质传送的传输介质或信号,例如电、电磁或数字信号。

如图中所示和在本文描述的各种方法表示方法的示例性实施例。方法可以在软件、硬件或其组合中实现。在各种方法中,步骤的次序可以改变,并且各种元素可被添加、重新排序、组合、省略、修改等。各种步骤可以自动地(例如,没有被用户输入直接提示)和/或以编程方式(例如,根据程序指令)执行。

虽然本文已经参照具体实施例并在其上下文中描述了各种系统和方法,但是应当理解,这些实施例是说明性的并且本公开内容的范围不限于这些具体实施例。许多变化、修改、添加和改进是可能的。例如,在描述中识别出的方框和逻辑单元是用于理解所描述的实施例,而不意味着限制本公开内容。例如,在一些实施例中,被描述为由编译器120执行的动作、过程、方法、任务或功能可以由虚拟化的运行时环境140执行,反之亦然。此外,功能可以在本文所述的或利用不同术语描述的系统和方法的各种实现中以不同方式在方框中分离或组合。

这些实施例意在是说明性的而非限制性的。因而,可以为在本文中被描述为单个实例的部件提供多个实例。各种部件、操作和数据存储之间的边界在某种程度上是任意的,并且特定操作是在具体说明性配置的上下文中示出的。功能的其它分配是可以想到的并可以落入随后的例子的范围内。最后,在示例性配置中作为离散部件给出的结构和功能可被实现为组合结构或部件。

虽然上面已经详细描述了实施例,但是,一旦完全明白了以上公开内容,众多的变化和修改将变得显而易见。意在将以下权利要求解释为涵盖所有此类变化和修改。

当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1