关于作者

姓名:

性别:男

出生日期:--

地区:

联系电话:

QQ:--

婚否:保密
用户名:gogomin
笔名:gogomin
地区:
行业:其他

日历  

快速登录

+ 用户名:
+ 密 码:

在线留言



访问统计:
文章个数:30
评论个数:5
留言条数:18




Powered by BlogDriver 2.1

gogomin的博客

 

欢迎访问gogomin的博客

文章

Java虚拟机

Java虚拟机

一、什么是Java虚拟机

Java虚拟机是一个想象中的机器,在实际的计算机上通过软件模拟来实现。Java虚拟机有自己想象中的硬件,如处理器、堆栈、寄存器等,还具有相应的指令系统。

1.为什么要使用Java虚拟机

Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。

2.谁需要了解Java虚拟机

Java虚拟机是Java语言底层实现的基础,对Java语言感兴趣的人都应对Java虚拟机有个大概的了解。这有助于理解Java语言的一些性质,也有助于使用Java语言。对于要在特定平台上实现Java虚拟机的软件人员,Java语言的编译器作者以及要用硬件芯片实现Java虚拟机的人来说,则必须深刻理解Java虚拟机的规范。另外,如果你想扩展Java语言,或是把其它语言编译成Java语言的字节码,你也需要深入地了解Java虚拟机。

3.Java虚拟机支持的数据类型

Java虚拟机支持Java语言的基本数据类型如下:

byte://1字节有符号整数的补码
short://2字节有符号整数的补码
int://4字节有符号整数的补码
long://8字节有符号整数的补码
float://4字节IEEE754单精度浮点数
double://8字节IEEE754双精度浮点数
char://2字节无符号Unicode字符

几乎所有的Java类型检查都是在编译时完成的。上面列出的原始数据类型的数据在Java执行时不需要用硬件标记。操作这些原始数据类型数据的字节码(指令)本身就已经指出了操作数的数据类型,例如iadd、ladd、fadd和dadd指令都是把两个数相加,其操作数类型别是int、long、float和double。虚拟机没有给boolean(布尔)类型设置单独的指令。boolean型的数据是由integer指令,包括integer返回来处理的。boolean型的数组则是用byte数组来处理的。虚拟机使用IEEE754格式的浮点数。不支持IEEE格式的较旧的计算机,在运行Java数值计算程序时,可能会非常慢。

虚拟机支持的其它数据类型包括:
object//对一个Javaobject(对象)的4字节引用
returnAddress//4字节,用于jsr/ret/jsr-w/ret-w指令
注:Java数组被当作object处理。

虚拟机的规范对于object内部的结构没有任何特殊的要求。在Sun公司的实现中,对object的引用是一个句柄,其中包含一对指针:一个指针指向该object的方法表,另一个指向该object的数据。用Java虚拟机的字节码表示的程序应该遵守类型规定。Java虚拟机的实现应拒绝执行违反了类型规定的字节码程序。Java虚拟机由于字节码定义的限制似乎只能运行于32位地址空间的机器上。但是可以创建一个Java虚拟机,它自动地把字节码转换成64位的形式。从Java虚拟机支持的数据类型可以看出,Java对数据类型的内部格式进行了严格规定,这样使得各种Java虚拟机的实现对数据的解释是相同的,从而保证了Java的与平台无关性和可
移植性。

二、Java虚拟机体系结构

Java虚拟机由五个部分组成:一组指令集、一组寄存器、一个栈、一个无用单元收集堆(Garbage-collected-heap)、一个方法区域。这五部分是Java虚拟机的逻辑成份,不依赖任何实现技术或组织方式,但它们的功能必须在真实机器上以某种方式实现。

1.Java指令集

Java虚拟机支持大约248个字节码。每个字节码执行一种基本的CPU运算,例如,把一个整数加到寄存器,子程序转移等。Java指令集相当于Java程序的汇编语言。
Java指令集中的指令包含一个单字节的操作符,用于指定要执行的操作,还有0个或多个操作数,提供操作所需的参数或数据。许多指令没有操作数,仅由一个单字节的操作符构成。

虚拟机的内层循环的执行过程如下:

do{
取一个操作符字节;
根据操作符的值执行一个动作;
}while(程序未结束)

由于指令系统的简单性,使得虚拟机执行的过程十分简单,从而有利于提高执行的效率。指令中操作数的数量和大小是由操作符决定的。如果操作数比一个字节大,那么它存储的顺序是高位字节优先。例如,一个16位的参数存放时占用两个字节,其值为:

第一个字节*256+第二个字节字节码指令流一般只是字节对齐的。指令tableswitch和lookup是例外,在这两条指令内部要求强制的4字节边界对齐。

2.寄存器

Java虚拟机的寄存器用于保存机器的运行状态,与微处理器中的某些专用寄存器类似。

Java虚拟机的寄存器有四种:
pc:Java程序计数器。
optop:指向操作数栈顶端的指针。
frame:指向当前执行方法的执行环境的指针。
vars:指向当前执行方法的局部变量区第一个变量的指针。

Java虚拟机

Java虚拟机是栈式的,它不定义或使用寄存器来传递或接受参数,其目的是为了保证指令集的简洁性和实现时的高效性(特别是对于寄存器数目不多的处理器)。
所有寄存器都是32位的。

3.栈

Java虚拟机的栈有三个区域:局部变量区、运行环境区、操作数区。

(1)局部变量区 每个Java方法使用一个固定大小的局部变量集。它们按照与vars寄存器的字偏移量来寻址。局部变量都是32位的。长整数和双精度浮点数占据了两个局部变量的空间,却按照第一个局部变量的索引来寻址。(例如,一个具有索引n的局部变量,如果是一个双精度浮点数,那么它实际占据了索引n和n+1所代表的存储空间。)虚拟机规范并不要求在局部变量中的64位的值是64位对齐的。虚拟机提供了把局部变量中的值装载到操作数栈的指令,也提供了把操作数栈中的值写入局部变量的指令。

(2)运行环境区 在运行环境中包含的信息用于动态链接,正常的方法返回以及异常传播。

·动态链接
运行环境包括对指向当前类和当前方法的解释器符号表的指针,用于支持方法代码的动态链接。方法的class文件代码在引用要调用的方法和要访问的变量时使用符号。动态链接把符号形式的方法调用翻译成实际方法调用,装载必要的类以解释还没有定义的符号,并把变量访问翻译成与这些变量运行时的存储结构相应的偏移地址。动态链接方法和变量使得方法中使用的其它类的变化不会影响到本程序的代码。

·正常的方法返回
如果当前方法正常地结束了,在执行了一条具有正确类型的返回指令时,调用的方法会得到一个返回值。执行环境在正常返回的情况下用于恢复调用者的寄存器,并把调用者的程序计数器增加一个恰当的数值,以跳过已执行过的方法调用指令,然后在调用者的执行环境中继续执行下去。

·异常和错误传播
异常情况在Java中被称作Error(错误)或Exception(异常),是Throwable类的子类,在程序中的原因是:①动态链接错,如无法找到所需的class文件。②运行时错,如对一个空指针的引用

·程序使用了throw语句。
当异常发生时,Java虚拟机采取如下措施:
·检查与当前方法相联系的catch子句表。每个catch子句包含其有效指令范围,能够处理的异常类型,以及处理异常的代码块地址。
·与异常相匹配的catch子句应该符合下面的条件:造成异常的指令在其指令范围之内,发生的异常类型是其能处理的异常类型的子类型。如果找到了匹配的catch子句,那么系统转移到指定的异常处理块处执行;如果没有找到异常处理块,重复寻找匹配的catch子句的过程,直到当前方法的所有嵌套的catch子句都被检查过。
·由于虚拟机从第一个匹配的catch子句处继续执行,所以catch子句表中的顺序是很重要的。因为Java代码是结构化的,因此总可以把某个方法的所有的异常处理器都按序排列到一个表中,对任意可能的程序计数器的值,都可以用线性的顺序找到合适的异常处理块,以处理在该程序计数器值下发生的异常情况。
·如果找不到匹配的catch子句,那么当前方法得到一个"未截获异常"的结果并返回到当前方法的调用者,好像异常刚刚在其调用者中发生一样。如果在调用者中仍然没有找到相应的异常处理块,那么这种错误传播将被继续下去。如果错误被传播到最顶层,那么系统将调用一个缺省的异常处理块。
(3)操作数栈区 机器指令只从操作数栈中取操作数,对它们进行操作,并把结果返回到栈中。选择栈结构的原因是:在只有少量寄存器或非通用寄存器的机器(如Intel486)上,也能够高效地模拟虚拟机的行为。操作数栈是32位的。它用于给方法传递参数,并从方法接收结果,也用于支持操作的参数,并保存操作的结果。例如,iadd指令将两个整数相加。相加的两个整数应该是操作数栈顶的两个字。这两个字是由先前的指令压进堆栈的。这两个整数将从堆栈弹出、相加,并把结果压回到操作数栈中。

每个原始数据类型都有专门的指令对它们进行必须的操作。每个操作数在栈中需要一个存储位置,除了long和double型,它们需要两个位置。操作数只能被适用于其类型的操作符所操作。例如,压入两个int类型的数,如果把它们当作是一个long类型的数则是非法的。在Sun的虚拟机实现中,这个限制由字节码验证器强制实行。但是,有少数操作(操作符dupe和swap),用于对运行时数据区进行操作时是不考虑类型的。

4.无用单元收集堆

Java的堆是一个运行时数据区,类的实例(对象)从中分配空间。Java语言具有无用单元收集能力:它不给程序员显式释放对象的能力。Java不规定具体使用的无用单元收集算法,可以根据系统的需求使用各种各样的算法。

5.方法区

方法区与传统语言中的编译后代码或是Unix进程中的正文段类似。它保存方法代码(编译后的java代码)和符号表。在当前的Java实现中,方法代码不包括在无用单元收集堆中,但计划在将来的版本中实现。每个类文件包含了一个Java类或一个Java界面的编译后的代码。可以说类文件是Java语言的执行代码文件。为了保证类文件的平台无关性,Java虚拟机规范中对类文件的格式也作了详细的说明。其具体细节请参考Sun公司的Java虚拟机规范。

- 作者: gogomin 2005年12月31日, 星期六 15:37  回复(0) |  引用(0) 加入博采

Java虚拟机

Java虚拟机

一、什么是Java虚拟机

Java虚拟机是一个想象中的机器,在实际的计算机上通过软件模拟来实现。Java虚拟机有自己想象中的硬件,如处理器、堆栈、寄存器等,还具有相应的指令系统。

1.为什么要使用Java虚拟机

Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。

2.谁需要了解Java虚拟机

Java虚拟机是Java语言底层实现的基础,对Java语言感兴趣的人都应对Java虚拟机有个大概的了解。这有助于理解Java语言的一些性质,也有助于使用Java语言。对于要在特定平台上实现Java虚拟机的软件人员,Java语言的编译器作者以及要用硬件芯片实现Java虚拟机的人来说,则必须深刻理解Java虚拟机的规范。另外,如果你想扩展Java语言,或是把其它语言编译成Java语言的字节码,你也需要深入地了解Java虚拟机。

3.Java虚拟机支持的数据类型

Java虚拟机支持Java语言的基本数据类型如下:

byte://1字节有符号整数的补码
short://2字节有符号整数的补码
int://4字节有符号整数的补码
long://8字节有符号整数的补码
float://4字节IEEE754单精度浮点数
double://8字节IEEE754双精度浮点数
char://2字节无符号Unicode字符

几乎所有的Java类型检查都是在编译时完成的。上面列出的原始数据类型的数据在Java执行时不需要用硬件标记。操作这些原始数据类型数据的字节码(指令)本身就已经指出了操作数的数据类型,例如iadd、ladd、fadd和dadd指令都是把两个数相加,其操作数类型别是int、long、float和double。虚拟机没有给boolean(布尔)类型设置单独的指令。boolean型的数据是由integer指令,包括integer返回来处理的。boolean型的数组则是用byte数组来处理的。虚拟机使用IEEE754格式的浮点数。不支持IEEE格式的较旧的计算机,在运行Java数值计算程序时,可能会非常慢。

虚拟机支持的其它数据类型包括:
object//对一个Javaobject(对象)的4字节引用
returnAddress//4字节,用于jsr/ret/jsr-w/ret-w指令
注:Java数组被当作object处理。

虚拟机的规范对于object内部的结构没有任何特殊的要求。在Sun公司的实现中,对object的引用是一个句柄,其中包含一对指针:一个指针指向该object的方法表,另一个指向该object的数据。用Java虚拟机的字节码表示的程序应该遵守类型规定。Java虚拟机的实现应拒绝执行违反了类型规定的字节码程序。Java虚拟机由于字节码定义的限制似乎只能运行于32位地址空间的机器上。但是可以创建一个Java虚拟机,它自动地把字节码转换成64位的形式。从Java虚拟机支持的数据类型可以看出,Java对数据类型的内部格式进行了严格规定,这样使得各种Java虚拟机的实现对数据的解释是相同的,从而保证了Java的与平台无关性和可
移植性。

二、Java虚拟机体系结构

Java虚拟机由五个部分组成:一组指令集、一组寄存器、一个栈、一个无用单元收集堆(Garbage-collected-heap)、一个方法区域。这五部分是Java虚拟机的逻辑成份,不依赖任何实现技术或组织方式,但它们的功能必须在真实机器上以某种方式实现。

1.Java指令集

Java虚拟机支持大约248个字节码。每个字节码执行一种基本的CPU运算,例如,把一个整数加到寄存器,子程序转移等。Java指令集相当于Java程序的汇编语言。
Java指令集中的指令包含一个单字节的操作符,用于指定要执行的操作,还有0个或多个操作数,提供操作所需的参数或数据。许多指令没有操作数,仅由一个单字节的操作符构成。

虚拟机的内层循环的执行过程如下:

do{
取一个操作符字节;
根据操作符的值执行一个动作;
}while(程序未结束)

由于指令系统的简单性,使得虚拟机执行的过程十分简单,从而有利于提高执行的效率。指令中操作数的数量和大小是由操作符决定的。如果操作数比一个字节大,那么它存储的顺序是高位字节优先。例如,一个16位的参数存放时占用两个字节,其值为:

第一个字节*256+第二个字节字节码指令流一般只是字节对齐的。指令tableswitch和lookup是例外,在这两条指令内部要求强制的4字节边界对齐。

2.寄存器

Java虚拟机的寄存器用于保存机器的运行状态,与微处理器中的某些专用寄存器类似。

Java虚拟机的寄存器有四种:
pc:Java程序计数器。
optop:指向操作数栈顶端的指针。
frame:指向当前执行方法的执行环境的指针。
vars:指向当前执行方法的局部变量区第一个变量的指针。

Java虚拟机

Java虚拟机是栈式的,它不定义或使用寄存器来传递或接受参数,其目的是为了保证指令集的简洁性和实现时的高效性(特别是对于寄存器数目不多的处理器)。
所有寄存器都是32位的。

3.栈

Java虚拟机的栈有三个区域:局部变量区、运行环境区、操作数区。

(1)局部变量区 每个Java方法使用一个固定大小的局部变量集。它们按照与vars寄存器的字偏移量来寻址。局部变量都是32位的。长整数和双精度浮点数占据了两个局部变量的空间,却按照第一个局部变量的索引来寻址。(例如,一个具有索引n的局部变量,如果是一个双精度浮点数,那么它实际占据了索引n和n+1所代表的存储空间。)虚拟机规范并不要求在局部变量中的64位的值是64位对齐的。虚拟机提供了把局部变量中的值装载到操作数栈的指令,也提供了把操作数栈中的值写入局部变量的指令。

(2)运行环境区 在运行环境中包含的信息用于动态链接,正常的方法返回以及异常传播。

·动态链接
运行环境包括对指向当前类和当前方法的解释器符号表的指针,用于支持方法代码的动态链接。方法的class文件代码在引用要调用的方法和要访问的变量时使用符号。动态链接把符号形式的方法调用翻译成实际方法调用,装载必要的类以解释还没有定义的符号,并把变量访问翻译成与这些变量运行时的存储结构相应的偏移地址。动态链接方法和变量使得方法中使用的其它类的变化不会影响到本程序的代码。

·正常的方法返回
如果当前方法正常地结束了,在执行了一条具有正确类型的返回指令时,调用的方法会得到一个返回值。执行环境在正常返回的情况下用于恢复调用者的寄存器,并把调用者的程序计数器增加一个恰当的数值,以跳过已执行过的方法调用指令,然后在调用者的执行环境中继续执行下去。

·异常和错误传播
异常情况在Java中被称作Error(错误)或Exception(异常),是Throwable类的子类,在程序中的原因是:①动态链接错,如无法找到所需的class文件。②运行时错,如对一个空指针的引用

·程序使用了throw语句。
当异常发生时,Java虚拟机采取如下措施:
·检查与当前方法相联系的catch子句表。每个catch子句包含其有效指令范围,能够处理的异常类型,以及处理异常的代码块地址。
·与异常相匹配的catch子句应该符合下面的条件:造成异常的指令在其指令范围之内,发生的异常类型是其能处理的异常类型的子类型。如果找到了匹配的catch子句,那么系统转移到指定的异常处理块处执行;如果没有找到异常处理块,重复寻找匹配的catch子句的过程,直到当前方法的所有嵌套的catch子句都被检查过。
·由于虚拟机从第一个匹配的catch子句处继续执行,所以catch子句表中的顺序是很重要的。因为Java代码是结构化的,因此总可以把某个方法的所有的异常处理器都按序排列到一个表中,对任意可能的程序计数器的值,都可以用线性的顺序找到合适的异常处理块,以处理在该程序计数器值下发生的异常情况。
·如果找不到匹配的catch子句,那么当前方法得到一个"未截获异常"的结果并返回到当前方法的调用者,好像异常刚刚在其调用者中发生一样。如果在调用者中仍然没有找到相应的异常处理块,那么这种错误传播将被继续下去。如果错误被传播到最顶层,那么系统将调用一个缺省的异常处理块。
(3)操作数栈区 机器指令只从操作数栈中取操作数,对它们进行操作,并把结果返回到栈中。选择栈结构的原因是:在只有少量寄存器或非通用寄存器的机器(如Intel486)上,也能够高效地模拟虚拟机的行为。操作数栈是32位的。它用于给方法传递参数,并从方法接收结果,也用于支持操作的参数,并保存操作的结果。例如,iadd指令将两个整数相加。相加的两个整数应该是操作数栈顶的两个字。这两个字是由先前的指令压进堆栈的。这两个整数将从堆栈弹出、相加,并把结果压回到操作数栈中。

每个原始数据类型都有专门的指令对它们进行必须的操作。每个操作数在栈中需要一个存储位置,除了long和double型,它们需要两个位置。操作数只能被适用于其类型的操作符所操作。例如,压入两个int类型的数,如果把它们当作是一个long类型的数则是非法的。在Sun的虚拟机实现中,这个限制由字节码验证器强制实行。但是,有少数操作(操作符dupe和swap),用于对运行时数据区进行操作时是不考虑类型的。

4.无用单元收集堆

Java的堆是一个运行时数据区,类的实例(对象)从中分配空间。Java语言具有无用单元收集能力:它不给程序员显式释放对象的能力。Java不规定具体使用的无用单元收集算法,可以根据系统的需求使用各种各样的算法。

5.方法区

方法区与传统语言中的编译后代码或是Unix进程中的正文段类似。它保存方法代码(编译后的java代码)和符号表。在当前的Java实现中,方法代码不包括在无用单元收集堆中,但计划在将来的版本中实现。每个类文件包含了一个Java类或一个Java界面的编译后的代码。可以说类文件是Java语言的执行代码文件。为了保证类文件的平台无关性,Java虚拟机规范中对类文件的格式也作了详细的说明。其具体细节请参考Sun公司的Java虚拟机规范。

- 作者: gogomin 2005年12月31日, 星期六 15:31  回复(0) |  引用(0) 加入博采

浅谈Java中的存储空间类型
浅谈Java中的存储空间类型
在Thinking in java里,列举了Java的六种存储类型
1.寄存器
编写过汇编程序的应该对寄存器非常熟悉,那时候用的ax,bx,cx,dx等等。寄存器在CPU里面,所以速度特别快,但是数量非常有限。在java中无法直接和寄存器打交道,不过在c中是可以声明寄存器变量的。

2.栈空间
写过汇编的肯定感到非常亲切,在汇编程序里不就是压栈和出栈吗?有一个指针控制栈空间,分配空间是栈指针上移,就是push操作,释放空间指针下移,就是pop操作。当然C和C++也主要是通过栈分配空间的。因为只要压栈和出栈,所以速度特别快。java中的对象引用是通过栈分配的,而java对象不是通过栈分配的,这也是java效率相对差一些的原因吧。通过栈分配空间有一个限制就是必须在编译时确定空间大小,也就是程序运行前就应该可以知道运行时内存的情况。比如mov ax,4这条指令占用多少个字节在编译时是确定的。

3.堆空间
就是一个大的内存块,需要的时候就申请分配,java中的对象都是在堆中非配的。但是堆空间的回收是比较麻烦的,所以JVM的回收算法都比较复杂。但是如果堆空间比较大,也就是内存没有面临用完的话,JVM一般不会启动垃圾回收器。这种情况下堆的效率和栈应该差不多,只是堆没有回收空间而已。如果要不时的启动GC的话,可以想象效率会极其低下。

4.静态存储区
声明为static的变量因为他们一直存在(整个程序运行过程中),所以他们被保存在一个静态存储区。

5.常量储存区
声明为final static的为常量,可以保存在常量储存区,还有String类型的对象都是常量,系统维护了一个String常量池。

6.其他存储
非RAM存储器,主要就是磁带,磁盘等等。

这里最关键的应该是栈和堆,栈应该是应用最广泛的,在汇编中函数调用的时候一般是这样的过程:
1.压栈(保护现场)
2.进入方法调用
3.出栈(恢复现场)
这里只是简单的描述,上面的过程可能会有好多嵌套,不过大致过程就是这样,在其他语言其实也是一样的。

- 作者: gogomin 2005年12月31日, 星期六 13:13  回复(0) |  引用(0) 加入博采

关于Java栈与堆的思考
 1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

  2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

  3. Java中的数据类型有两种。

  一种是基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。

  另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3;
int b = 3;

  编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。

  特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。

  另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。 4. String是一个特殊的包装类数据。即可以用String str = new String("abc");的形式来创建,也可以用String str = "abc";的形式来创建(作为对比,在JDK 5.0之前,你从未见过Integer i = 3;的表达式,因为类与字面值是不能通用的,除了String。而在JDK 5.0中,这种表达式是可以的!因为编译器在后台进行Integer i = new Integer(3)的转换)。前者是规范的类的创建过程,即在Java中,一切都是对象,而对象是类的实例,全部通过new()的形式来创建。Java中的有些类,如DateFormat类,可以通过该类的getInstance()方法来返回一个新创建的类,似乎违反了此原则。其实不然。该类运用了单例模式来返回类的实例,只不过这个实例是在该类内部通过new()来创建的,而getInstance()向外部隐藏了此细节。那为什么在String str = "abc";中,并没有通过new()来创建实例,是不是违反了上述原则?其实没有。

  5. 关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:

  (1)先定义一个名为str的对String类的对象引用变量:String str;

  (2)在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并返回o的地址。

  (3)将str指向对象o的地址。

  值得注意的是,一般String类中字符串值都是直接存值的。但像String str = "abc";这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用!

  为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true

  注意,我们这里并不用str1.equals(str2);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,str1与str2是否都指向了同一个对象。
结果说明,JVM创建了两个引用str1和str2,但只创建了一个对象,而且两个引用都指向了这个对象。

  我们再来更进一步,将以上代码改成:

String str1 = "abc";
String str2 = "abc";
str1 = "bcd";
System.out.println(str1 + "," + str2); //bcd, abc
System.out.println(str1==str2); //false

  这就是说,赋值的变化导致了类对象引用的变化,str1指向了另外一个新对象!而str2仍旧指向原来的对象。上例中,当我们将str1的值改为"bcd"时,JVM发现在栈中没有存放该值的地址,便开辟了这个地址,并创建了一个新的对象,其字符串的值指向这个地址。

  事实上,String类被设计成为不可改变(immutable)的类。如果你要改变其值,可以,但JVM在运行时根据新值悄悄创建了一个新对象,然后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的,但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中,会带有一定的不良影响。

  再修改原来代码:

String str1 = "abc";
String str2 = "abc";

str1 = "bcd";

String str3 = str1;
System.out.println(str3); //bcd

String str4 = "bcd";
System.out.println(str1 == str4); //true

  str3这个对象的引用直接指向str1所指向的对象(注意,str3并没有创建新对象)。当str1改完其值后,再创建一个String的引用str4,并指向因str1修改值而创建的新的对象。可以发现,这回str4也没有创建新的对象,从而再次实现栈中数据的共享。

  我们再接着看以下的代码。

String str1 = new String("abc");
String str2 = "abc";
System.out.println(str1==str2); //false

  创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。

String str1 = "abc";
String str2 = new String("abc");
System.out.println(str1==str2); //false

  创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。

  以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。

  6. 数据类型包装类的值不可修改。不仅仅是String类的值不可修改,所有的数据类型包装类都不能更改其内部的值。 7. 结论与建议:

  (1)我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,我们创建了String类的对象str。担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向String类的引用被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。因此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为"abc"的String类。清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。

  (2)使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。这个思想应该是享元模式的思想,但JDK的内部在这里实现是否应用了这个模式,不得而知。

  (3)当比较包装类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==。

  (4)由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。

- 作者: gogomin 2005年12月31日, 星期六 12:09  回复(0) |  引用(0) 加入博采

中信证券数量化分析系统简介

1. 开发本系统的目的
☆ 为金融工程的数量化研究提供一个有效的数据和工具平台。
☆ 为研究报告提供统一的管理平台。
☆ 把证券市场主要的投资分析活动进行整合,使分析更全面、深入、有效。
☆ 摆脱原有一个客户一套数据库的旧模式,让所有用户共用同一底层数据库,使数据更准确、更新更及时。


2. 系统主要模块

2.1 股票分析
主要针对数量化分析所用到的所有结构化数据进行各种分类统计分析。
2.2 基金分析
在现有的基金信息披露程度上,能够准确分析出基金的投资、持股风格和风险收益状况,为投资者提供了一个深入分析基金业绩的工具。
2.3 债券分析
为债券组合的投资提供一个深入、全面、有效的分析工具。目前主要包括:债券基本信息和行情信息查询;债券指数行情查询分析;利率期限结构分析;情景分析;投资组合分析;新券定价分析。
2.4 组合分析
2.4.1 指数
是投资分析最基础、最常用的工具,用户可以自定义任意组合为一个指数,用于组合的历史模拟及实证分析研究。主要包括:用户自定义指数、指数叠加分析、指数点位、指数样本股及权重、指数的财务及风险指标分析等。
2.4.2 指数增强/Alpha预测
对标的指数样本股在未来一定时期的超额收益率进行预测(预测方法:多因子模型/横截面回归)。通过预测结果对指数中超额收益率高的样本股加大权重,低的减少权重,以此来达到指数增强的目的。
2.4.3 优化资产配置
针对用户对各资产类的期望收益率和风险、投资比例等约束条件,给出资金在各资产类上的最优投资比例。用户权衡每一个资产配置以后,从中选择满足自己要求的最优资产配置。
2.4.4 构建最优组合
根据用户对自定义组合中各股超额收益率的预测结果,使用风险模型和标准的二次规划方法对用户组合中各股的权重进行优化。
2.4.5 优化指数策略
使用风险模型并考虑到交易费用及市值规模对指数的投资策略进行优化。
2.4.6 组合风险分析
该模块可以揭示任意组合相对于任意基准在任何时点的各项风险指标,以便用户对组合的风险进行及时的控制。
2.4.7 自建风险模型
用户只需要选择风险因子并指定必要的参数,系统就会自动通过横截面回归和时间序列回归为用户构建出自己的风险模型。
2.5 研究报告浏览
提供研究报告的统一管理平台,用户可以方便快捷的浏览、查询、下载我们提供的所有研究报告。
2.6 矩阵运算工具
提供了一个简易高效的矩阵运算工具,用户可以方便的进行矩阵的各种运算,为金融数量化分析(特别是大数据量的回归)提供强有力的工具支持。

3. 其他定制模块
3.1 基金绩效评估
主要针对基金公司内部交易系统及估值系统的数据结合市场上其它基金的公开数据进行各种统计分析,对各基金的运作绩效作出及时的评估,对本公司基金的收益和风险状况进行全面的分析和监控,以便基金管理人及时调整本公司基金的投资策略。
3.2 指数基金的归因分析
主要用于计算指数基金的跟踪误差和偏离度,以便及时将误差控制在指定范围内。

 


4. 股票分析
主要针对数量化分析所用到的所有结构化数据进行各种分类统计分析。主要包括:
4.1 行情数据
各证券及中信系列指数每日的行情数据、换手率、复权价、EP、BP、收益率、及以上各项的平均值(任一期间的平均换手率、平均市值等)、统计值(任一期间涨幅、振幅等)等,并提供股票及指数的叠加走势分析功能。
4.2 历次分红送配及股本变动情况
各股的最新股本结构、历次分红、送股、配股、增发等
4.3 三大财务报表及常用财务指标
4.4 行业分类(证监会及中信两套行业分类标准)
4.5 上市发行
发行日、上市日、发行方式、发行价、发行市盈率、首日开盘价等信息
4.6 所属的中信系列指数
4.7 各种数据的综合选股

5. 基金分析
主要针对基金公开的净值及季报、年报数据进行各种分类统计,对市场上所有基金(包括封闭式和开放式)进行各种横向比较分析,从收益率、风险、风险调整收益、业绩贡献、风险来源等方面对资产运作状况进行综合评估,以确定不同基金的投资风格,为您的基金投资提供参考。功能如下:
5.1 净值及季报数据的分析
主要包括:行情数据分析、净值数据分析、股票组合分析、行业组合分析、及一级资产配置分析等,同时系统可提供各种统计分析图表。具体如下:
5.1.1 行情数据分析
用于查询所有基金的市场价格数据,并可绘制出任意几个基金的价格走势叠加图,便于对各个基金的二级市场表现做出叠加对比分析。
5.1.2 净值数据分析
可以查询市场上所有基金的单位净值、复权净值、分红信息、收益率、折价率等信息,同时可以绘制出任意几个基金的单位净值、复权净值、折价率和任意几个市场指数点位的叠加走势图,便于对基金收益情况相对于市场的表现做出准确的分析判断。
5.1.3 股票组合分析
用于查询任意基金在任意季度的前十大重仓股信息(第几大重仓股、持有的数量、市值、占净值及股票总市值的比例等),同时可以绘制出任意基金的重仓股分布饼型图,也可以按照股票查询出市场上的所有基金的持有情况,并可绘制出所有持有该股票的基金的持有情况对比图,以便对所有基金持有的重仓股做出对比分析。
5.1.4 行业组合分析
和上述的股票组合分析在功能上类似,可以查询任意基金在任意季度的所有行业组合信息(第几大重仓行业、持有的总市值、占净值及股票总市值的比例等),同时可以绘制出任意基金的行业配置饼型图,也可以按照行业查询出市场上的所有基金的持有情况,并可绘制出行业持有情况对比图,以便对所有基金持有的行业市值做出对比分析。
5.1.5 资产配置分析
主要用于查询所有基金的一级资产配置情况(股票总市值及占净值的比例、债券总市值及占净值的比例),并可绘制出各基金的一级资产配置情况对比图,使表现更为直观。
5.2 年报数据的分析
主要包括: 期末持仓、受限股票、新增股票、剔除股票、基金财务报表、股票交易情况、债券交易情况、持有人信息、及基本信息等的查询分析,同时系统可提供各种统计分析图表。具体如下:
5.2.1 期末持仓
用于查询分析基金年报公布的所有投资组合信息。
5.2.2 受限股票
用于查询分析所有基金年报公布的所有受限股票信息。
5.2.3 新增股票
用于查询分析基金年报公布的所有新增股票信息。
5.2.4 剔除股票
用于查询分析基金年报公布的所有剔除股票信息。上述的四项(a,b,c,d)都可以按照股票来查询分析。
5.2.5 基金财务报表
用于查询分析基金年报公布的所有财务报表信息。
5.2.6 股票交易情况分析
可以查询分析所有基金在各券商的股票交易量及交易佣金分布情况,并可绘制出各个基金的交易佣金分布图,还可以按照券商来查各基金在该券商席位上的交易量及佣金情况,并可绘制出各基金在该券商席位上的佣金分布对比图,以便更全面的分析各基金的佣金分布及各券商的佣金收入构成。
5.2.7 债券交易情况分析
与上述的股票交易情况分析类似,这里就不再赘述。
5.2.8 持有人分析
可以查询分析各基金的持有人分布情况,并可绘制出指定基金的持有人分布图,同时可查询指定持有人对各基金的持有情况,也可以绘制出指定持有人对各基金的持有情况对比图。以便更直观的分析基金持有人的分布和持有人投资基金的情况。
5.3 综合统计分析
主要包括:收益及风险、持股变动情况、行业集中度、个股集中度、风险特征、基金集体重仓股等, 同时系统可提供各种统计分析图表。具体如下:
5.3.1 收益及风险分析
可以计算统计出各基金的期间累计净值增长率和标准差,并可绘制出各基金的收益及风险对比图,以便用户更全面的了解各基金的收益及风险状况,为用户的投资提供帮助。
5.3.2 持股变动分析
可以按照基金公布的重仓股统计出本季度相对于上季度的持股变动情况(包括:增持的、减持的、新增的、剔除的、持股不变的),该功能可为投资者分析基金近期的仓位变动情况提供有力的支持。
5.3.3 行业集中度分析
可以统计出各基金持有的指定行业的市值之和及占净值和股票总市值的比例,并可绘制出各基金的行业集中度对比图,以便用户对各基金的行业配置集中情况做出直观的分析判断。
5.3.4 个股集中度分析
与上述行业集中度的功能比较类似,可以统计出各基金持有的指定的前几个重仓股的市值之和及占净值和股票总市值的比例,并可绘制出各基金的个股集中度对比图,以便用户对各基金的个股投资集中情况做出直观的分析判断。
5.3.5 风险特征分析
可以计算出任意基金相对于任意基准(股票基准、债券基准)的各种常用风险指标(包括:标准差、Beta系数、Alpha、非系统风险、夏普指数、夏普指数、詹森指数、特雷诺指数等),同时可绘制出各基金的上述各风险指标对比图,以便用户对各基金的风险分布情况进行全面的了解。
5.3.6 集体重仓股分析
可以统计任意一个季度所有基金的集体重仓股信息(包括:持有的总数量、持有的总市值、占基金总净值的比例、占基金总股票市值的比例、及持有的基金名称等),以便用户全面了解各基金的集体持仓情况。
5.4 中信o基金评级
可按用户指定的风险接受程度对各基金按照《中信o基金评级准则》中的方法进行评级,使用户能够对各基金的收益和风险情况进行全面的分析。

 

6. 债券分析
债券投资分析系统目前包含的主要功能模块有:债券基本信息和行情信息查询;债券指数行情查询;利率期限结构分析;情景分析;投资组合分析。各个模块主要实现的功能如下:
6.1 债券基本信息和行情信息分析
查询债券市场上所有未到期和已经到期的债券的基本信息,如期限,票面利率,发行日期,发行量,发行人,发行方式,付息方式和频率等,和某一日期的所有有交易债券的行情信息,如净价,全价,成交额等。
6.2 债券指数行情的查询分析
提供多个债券指数(包括交易所国债指数,企业债指数,银行间债券指数,银行间国债指数,银行间金融债指数,全债指数,可转债指数等)的历史行情数据,并提供指数的样本券和指数组合的在不同时点的久期等。对于每一个指数,将分别提供相同样本集合的净价指数和全价指数。
6.3 收益率期限结构分析
包括收益率期限结构分析和收益率期限结构的比较分析两个基本功能。前者是生成由某个债券集合(如交易所国债集合,用户可以通过编辑生成任意的债券集合)所决定的收益率期限结构图。后者是对两个债券集合(如交易所国债集合和交易所企业债集合)所决定的收益率期限结构进行比较分析。
6.4 情景分析
分析在未来收益率期限曲线发生位置和结构变化时,某只债券或某个债券组合的潜在的净值变动的风险。对于未来收益率期限结构的变化,系统共设置了10种可能的变化情况,其中包括平行移动,以及非平行移动和反转等位置和结构变化情况,同时系统允许用户设置各种变化的幅度。
对债券或者某个债券组合的潜在的净值变动的风险主要通过潜在净价和全价的变化幅度等来衡量。
6.5 债券组合分析
分析一个债券组合的基本信息,包括组合中的每一只债券的票面信息和收益率,久期,凸性,以及流动性和相对投资价值指标等信息。显示一个或多个组合的历史净值走势,以及各个组合在某个时点的净值和久期等指标。
6.6 新券定价分析
分为普通债券定价分析,浮动利息债券定价分析和含权债券分析。
普通债券是指不含权的债券,含权债券目前主要是指可赎回债券,可回售债券和可转换债券等,系统根据用户输入的债券的基本条款,如票面利率,期限等,输出相应的定价分析。其中对于可赎回债券,可回售债券的定价,目前系统采用二叉树算法。

 

 


7. 组合分析

7.1 指数
是投资分析最基础、最常用的工具,用户可以自定义任意组合为一个指数,用于组合的历史模拟及实证分析研究。中信系列指数就是用该工具实时计算并对外发布的。主要功能如下:
7.1.1 指数定义
包括:指数名称,基准日期,基期点位,加权方式,指数的样本股定义。
7.1.2 指数计算
使用派氏加权法(与上海交易所的指数算法相同)计算用户指定的指数点位,还可以同时计算出指数的各种财务指标(每股净资产BPS、每股收益EPS、市盈率PE、净市值比BP、平均流通市值等)和风险指标(Beta、Alpha、非系统风险、标准差、夏普比率、特雷诺指数、詹森指数等)。
7.1.3 指数叠加分析
可随意选定用户自定义指数及市场指数、任意股票从同一个起点绘制走势叠加图(系统自动将选定指数的点位统一按比例换算成同一个指数的点位,以保证多个指数是从同一个起点开始的),便于分析同一个时期那个指数或股票表现的更好。
7.1.4 指数数据的浏览及导出
7.2 指数增强/Alpha预测
对标的指数样本股在未来一定时期的超额收益率进行预测(预测方法:多因子模型\横截面回归),根据预测结果,将指数的样本股分成三类:预期超额收益率最大的部分股票权重增加,预期超额收益率最小的部分股票权重下降,其余股票的权重与基准指数一致。
风险因子有6个基本因子、15个补充因子及4个行业因子,用户在做超额收益率预测时,可以挑选以上任意几个风险因子,也可以加入自定义的风险因子。6个基本因子包括:流通市值、净市值比、换手率、动量、收入价格比、价格波动率;15个补充因子包括:每股公积金比股价、现金流比股价、股利收益率、市盈率、流通盘规模、每股留存收益比股价、应收账款周转率、财务杠杆比例、存货周转率、主营业务利润比重、主营业务利润率、主营业务收入变化、主营业务毛利率、净资产收益率、流通股比例;4个行业因子包括:证监会一级行业、证监会二级行业、中信一级行业、中信二级行业。
7.3 优化资产配置
针对用户要配置的各资产类的期望收益率和风险等约束条件,给出资金在各类资产之间的投资比例。用户权衡每一个资产配置以后,从中选择满足自己要求的最优资产配置。整个系统包括参数数入、优化配置、结果输出三大部分:
参数数入:输入要进行配置的各资产类(股票、债券、货币或股票市场中的各类风格、行业资产等)的期望收益率及协方差矩阵。这两个参数可以由系统根据历史数据自动生成,还可以通过风险模型计算得到。同时用户还可以输入各种约束条件,(如:各资产类的投资比例约束、整个投资组合的VaR约束等)。
优化配置:根据用户输入的参数及约束条件,通过标准的二次规划方法求出在不同期望收益下的资产配置比例,并给出每个组合的标准差、Sharpe比等指标。
结果输出:将资产配置的结果用图形和表格的形式来表示。系统会按照配置结果绘制出均值-方差的有效前沿面,对于一些重要的点,比如Sharpe比最大的点、满足用户要求的点等特别表示,同时对前沿面上的每个投资组合点,系统都会绘制出相应的资产配置饼型图。在表格输出部分,用户可以详细了解每个可选资产组合中每一类资产的投资比例、投资组合的期望收益率、标准差、Var、Sharpe比等指标,即每一种资产组合方案的收益-风险状况、相互之间的优劣比较,用于辅助决策。同时会给出系统推荐的资产配置。
7.4 构建最优组合
根据用户对自定义组合中各股超额收益率的预测结果,使用风险模型对用户组合中各股的权重进行优化。过程如下:
输入:用户组合中各股的超额收益率,风险接受程度,指定基准指数及使用的风险模型。
构建:假设投资者对系统风险和非系统风险的规避程度相同,可以将目标函数转化为最小化问题,用标准的二次规划方法来构建最优组合。
输出:用户组合中各股的最优权重。
7.5 优化指数策略
使用风险模型并考虑到交易费用及市值规模对指数的投资策略进行优化。过程如下:
输入:要投资的指数,交易税率,投资的市值规模,使用的风险模型。
优化:将目标函数转化为最小化问题,用标准的二次规划方法来优化。
输出:投资时指数中各样本的最优市值权重。
7.6 组合风险分析
该模块可以揭示任意组合相对于任意基准在任何时点的各项风险指标,以便用户对组合的风险进行及时的控制。
主要的风险指标如下:均值,方差,标准差,半方差;相对于基准组合及本身组合的Beta系数,Alpha,Var(包括:边际Var、成分Var,三种算法:简单算法,RiskMetrics算法,偏度\峰度算法),流动性风险,变现损失率等。
7.7 自建风险模型
通过指定股票组合及风险因子(与Alpha预测模块的风险因子相同)在指定周期的历史横截面回归估计出各因子的收益率序列, 接着通过历史时间序列回归估计出各因子的载荷,至此就构建成了用户自己的风险模型(两个文件:N个股票对K个风险因子的系数矩阵文件和K个风险因子的协方差矩阵文件),用户在要使用风险模型的地方只要指定这两个模型文件即可。

 

 


8. 其他定制模块
8.1 基金绩效评估
主要针对基金公司内部交易系统及估值系统的数据结合市场上其它基金的公开数据进行各种统计分析,对各基金的运作绩效作出及时的评估,对本公司基金的收益和风险状况进行全面的分析和监控,以便基金管理人及时调整本公司基金的投资策略。主要包括以下六大模块:
8.1.1 投资组合
统计分析本公司基金的投资组合信息。包括:每日的基金净值信息,一级资产配置情况,持仓信息,重仓股信息等。
8.1.2 资产分布
分类统计投资组合中各类资产的分布情况,并与证券市场进行横向比较,可按行业或常用指标(用户自己分为不同的区间)统计各行业或各指标区间的股票资产分布情况,并与市场基准进行横向对比,充分了解本基金的资产分布情况。
常用指标包括:
☆ 财务指标(每股收益,净资产收益率,主营收入增长率,主营收入利润率,每股经营现金流量等);
☆ 股本结构(流通股本,总股本等);
☆ 市场属性(市盈率,市净率,股票价格,流通市值,总市值等)。
8.1.3 收益构成
可按行业或常用指标(用户自己分为不同的区间)统计各行业或各指标区间的股票收益情况及个股收益。
8.1.4 收益贡献
把基金的投资收益情况进行业绩的分解,包括:超额收益率,资产配置的贡献率,资产选择的贡献率,行业配置的贡献率,个股选择的贡献率,个股收益:统计分析各股的实际盈亏。
8.1.5 风险分析
对基金投资组合的各项风险进行全面的揭示。主要包括:
☆ 流动性风险(行业集中度,个股集中度,组合变现能力);
☆ Beta系数(基金的Beta及投资组合中各股的Beta);
☆ 投资组合中各股的超额收益率;
☆ VaR(三种算法计算基金的VaR及基金组合中各股的VaR);
☆ 信息比率(跟踪误差及信息比率);
☆ 风险特征(Beta,非系统风险,Alpha,标准差,夏普指数等)。
8.1.6 风险预警
对可能或超出限制的投资组合及时进行预警。主要包括:
☆ 行业预警:某行业市值超过设定值时进行警示;
☆ 股票预警:市值预警,成本预警,价格预警, 新仓预警;
☆ 流动性预警:当变现天数大于设定值时进行警示;
☆ 法规预警:双十规定预警,投资比例预警;
☆ 股票黑名单。
8.1.7 绩效报告
将上述五个模块中的重点指标进行提炼汇总,自动生成针对不同人员(各自基金的基金经理、投资总监等)的绩效分析报告。
8.2 指数基金的归因分析
主要用于计算指数基金的跟踪误差和偏离度,以便及时将误差控制在指定范围内。主要功能包括:
8.2.1 跟踪误差的归因分析
指数基金跟踪误差有两个主要来源:资产配置(股票投资比例与比较基准的投资比例有差异)、债券组合跟踪误差和个股投资权重与基准指数权重的差异。
每日计算日跟踪误差,并分解成以下几项:
☆ 资产配置产生的跟踪误差
☆ 国债投资产生的跟踪误差
☆ 个股增强产生的跟踪误差
☆ 其它权重差异产生的跟踪误差
☆ 交叉项跟踪误差
如果日跟踪误差超出指定范围,要及时进行报警。
8.2.2 股票组合跟踪偏离的归因分析
股票组合跟踪偏离主要来源:股票的增强投资造成的偏离,交易成本(包括价差和佣金)造成的偏离。
每日计算日累计跟踪偏离,并分解成以下几项:
权重偏离:
☆ 增强偏离
☆ 其它权重偏离
交易成本:
☆ 佣金印花税等
☆ 价差
说明:系统在此只将日跟踪误差及日累计跟踪偏离分解为上述各项,下一步的投资决策完全由基金管理者进行,系统不提供投资建议。


9. 联系人
中信证券研究部:于新力、李灏
服务热线:
010-84864818-61223 yxl@citics.com
010-84864818-63693 lihao@citics.com

- 作者: gogomin 2005年12月29日, 星期四 16:10  回复(1) |  引用(0) 加入博采

开源:www.open-open.com
开源:www.open-open.com

Spring Framework  【Java开源 J2EE框架】

Spring是一个解决了许多在J2EE开发中常见的问题的强大框架。 Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯。Spring的架构基础是基于使用JavaBean属性的Inversion of Control容器。然而,这仅仅是完整图景中的一部分:Spring在使用IoC容器作为构建完关注所有架构层的完整解决方案方面是独一无二的。 Spring提供了唯一的数据访问抽象,包括简单和有效率的JDBC框架,极大的改进了效率并且减少了可能的错误。Spring的数据访问架构还集成了Hibernate和其他O/R mapping解决方案。Spring还提供了唯一的事务管理抽象,它能够在各种底层事务管理技术,例如JTA或者JDBC事务提供一个一致的编程模型。Spring提供了一个用标准Java语言编写的AOP框架,它给POJOs提供了声明式的事务管理和其他企业事务--如果你需要--还能实现你自己的aspects。这个框架足够强大,使得应用程序能够抛开EJB的复杂性,同时享受着和传统EJB相关的关键服务。Spring还提供了可以和IoC容器集成的强大而灵活的MVC Web框架。【SpringIDE:Eclipse平台下一个辅助开发插件】.

WebWork  【Java开源 Web框架】

WebWork是由OpenSymphony组织开发的,致力于组件化和代码重用的拉出式MVC模式J2EE Web框架。WebWork目前最新版本是2.1,现在的WebWork2.x前身是Rickard Oberg开发的WebWork,但现在WebWork已经被拆分成了Xwork1和WebWork2两个项目。 Xwork简洁、灵活功能强大,它是一个标准的Command模式实现,并且完全从web层脱离出来。 Xwork提供了很多核心功能:前端拦截机(interceptor),运行时表单属性验证,类型转换,强大的表达式语言(OGNL – the Object Graph Notation Language),IoC(Inversion of Control倒置控制)容器等。 WebWork2建立在Xwork之上,处理HTTP的响应和请求。WebWork2使用ServletDispatcher将HTTP请求的变成Action(业务层Action类), session(会话)application(应用程序)范围的映射,request请求参数映射。WebWork2支持多视图表示,视图部分可以使用JSP, Velocity, FreeMarker, JasperReports,XML等。在WebWork2.2中添加了对AJAX的支持,这支持是构建在DWR与Dojo这两个框架的基础之上.【EclipseWork用于WebWork辅助开发的一个Eclipse插件

Struts  【Java开源 Web框架】

Struts是一个基于Sun J2EE平台的MVC框架,主要是采用Servlet和JSP技术来实现的。由于Struts能充分满足应用开发的需求,简单易用,敏捷迅速,在过去的一年中颇受关注。Struts把Servlet、JSP、自定义标签和信息资源(message resources)整合到一个统一的框架中,开发人员利用其进行开发时不用再自己编码实现全套MVC模式,极大的节省了时间,所以说Struts是一个非常不错的应用框架。【StrutsIDE用于Struts辅助开发的一个Eclipse插件

Hibernate  【Java开源 持久层框架】

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序实用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。Eclipse平台下的Hibernate辅助开发工具:【Hibernate Synchronizer】【MiddlegenIDE

Quartz  【Java开源 日程安排(Job Schedulers)】

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 1.5.0

Velocity  【Java开源 模板引擎】

Velocity是一个基于java的模板引擎(template engine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。 当Velocity应用于web开发时,界面设计人员可以和java程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员可以只关注页面的显示效果,而由java程序开发人员关注业务逻辑编码。Velocity将java代码从web页面中分离出来,这样为web站点的长期维护提供了便利,同时也为我们在JSP和PHP之外又提供了一种可选的方案。 Velocity的能力远不止web站点开发这个领域,例如,它可以从模板(template)产生SQL和PostScript、XML,它也可以被当作一个独立工具来产生源代码和报告,或者作为其他系统的集成组件使用。Velocity也可以为Turbine web开发架构提供模板服务(template service)。Velocity+Turbine提供一个模板服务的方式允许一个web应用以一个真正的MVC模型进行开发。 【VeloEclipse :Velocity在Eclipse平台下的一个辅助开发插件】

IBATIS  【Java开源 持久层框架】

使用ibatis 提供的ORM机制,对业务逻辑实现人员而言,面对的是纯粹的Java对象, 这一层与通过Hibernate 实现ORM 而言基本一致,而对于具体的数据操作,Hibernate 会自动生成SQL 语句,而ibatis 则要求开发者编写具体的SQL 语句。相对Hibernate等 “全自动”ORM机制而言,ibatis 以SQL开发的工作量和数据库移植性上的让步,为系统 设计提供了更大的自由空间。作为“全自动”ORM 实现的一种有益补充,ibatis 的出现显 得别具意义。

Compiere ERP  【Java开源 ERP与客户关系管理】

这一高价值的商业应用程序,易于安装、易于实施、易于使用。只需要短短几个小时,您就可以使用申购-采购-发票-付款、报价-订单-发票-收款、产品与定价、资产管理、客户关系、供应商关系、员工关系、经营业绩分析等强大功能了!功能未减,实施时间缩减到 4 小时。最重要的是:这一高价值的商业应用程序是免费的!可以自行安装和实施这套系统(如果您略懂 Oracle 和 Java 技术)。
中文站点:http://www.compiere-china.com/

Roller Weblogger   【Java开源 博客(Blog)】

这个weblogging 设计得比较精巧,源代码是很好的学习资料。它支持weblogging应有的特性如:评论功能,所见即所得HTML编辑,TrackBack,提供页面模板,RSS syndication,blogroll管理和提供一个XML-RPC 接口。

displytag  【Java开源 Jsp标签库】

与Struts结合使用最出名的一个tag主要是显示表格数据很漂亮、完善。

JFreeChart  【Java开源 报表制作】

JFreeChart它主要是用来制作各种各样的图表,这些图表包括:饼图、柱状图(普通柱状图以及堆栈柱状图)、线图、区域图、分布图、混合图、甘特图以及一些仪表盘等等。

Eclipse  【Java开源 开发工具】

Eclipse平台是IBM向开发源码社区捐赠的开发框架,它之所以出名并不是因为IBM宣称投入开发的资金总数 —4千万美元,而是因为如此巨大的投入所带来的成果:一个成熟的、精心设计的以及可扩展的体系结构。

Liferay  【Java开源 门户系统】

代表了完整的J2EE应用,使用了Web、EJB以及JMS等技术,特别是其前台界面部分使用Struts 框架技术,基于XML的portlet配置文件可以自由地动态扩展,使用了Web Services来支持一些远程信息的获取,使用 Apahce Lucene实现全文检索功能。
主要特点:
    1、提供单一登陆接口,多认证模式(LDAP或SQL);
    2、管理员能通过用户界面轻松管理用户,组,角色;
    3、用户能可以根据需要定制个性化的portal layout;
    4、能够在主流的J2EE应用服务器上运行,如JBoss+Jetty/Tomcat,JOnAS;
    5、支持主流的数据库,如PostgreSQL,MySQL;
    6、使用了第三放的开源项目,如Hibernate, Lucene, Struts;
    7、支持包括中文在内的多种语言;
    8、采用最先进的技术 Java, EJB, JMS, SOAP, XML;

JetSpeed  【Java开源 门户系统】

Jetspeed是一个开放源代码的企业信息门户(EIP)的实现, 使用的技术是Java和XML. 用户可以使用浏览器, 支持WAP协议的手机或者其它的设备访问Jetspeed架设的信息门户获取信息. Jetspeed扮演着信息集中器的角色, 它能够把信息集中起来并且很容易地提供给用户.
Jetspeed具有如下的特征:

* 即将成为标准化的Java Portlet API
* 基于模板的布局, 包括JSP和Velocity
* 通过开放的内容同步技术支持远程XML内容交换
* 定制默认的主页
* 使用数据库进行用户认证
* 内存缓存技术, 加快页面的响应
* 通过Rich Site Summary技术, 支持同步内容
* 和Cocoon, WebMacro, Velocity集成.
* Wireless Markup Language (WML) 支持
* 使用XML格式的配置文件注册portlet.
* 完整的Web Application Archive (WAR) 支持
* Web应用程序开发的基础设施
* 可以在本地缓存远程内容
* 与Avantgo同步
* 可移植到所有支持JDK1.2和Servlet 2.2的平台
* 与Turbine模块和服务集成
* 可以根据用户, 安装媒体类型和语言的不同设定, 产生不同的个性化服务
* 持续化服务使得所由的portlet能够容易的存储每个用户的状态, 页面和portlet
* 使用皮肤技术使得用户可以选择portlet的颜色和显示属性
* 自定义功能是的管理员可以选择portlet以及定义个人页面的布局
* 在数据库中存储PSML
* 通过Jetspeed的安全portlets管理用户, 组,角色和权限
* 基于角色对访问portlet进行控制

JOnAS  【Java开源 EJB服务器】

JOnAS是一个开放源代码的J2EE实现,在ObjectWeb协会中开发。整合了Tomcat或Jetty成为它的Web容器,以确保符合Servlet 2.3和JSP 1.2规范。JOnAS服务器依赖或实现以下的Java API:JCA、JDBC、JTA 、JMS、JMX、JNDI、JAAS、JavaMail 。

Turbine  【Java开源 Web框架】

Turbine是基于Servlet的框架包,也是开放源代码Jakarta项目。目前还没有关于Turbine的大量文档。它类似于Struts,但是有一些主要区别。突出的一点就是它并没有与JSP耦合。Turbine的特点是它提供了大量可重用的组件。此框架包中包含了大量组件,但是这些组件是离散的。它似乎应该给出更多的组件库,但是由于它缺少文档,所以很难掌握完整的体系结构。

Tapestry  【Java开源 Web框架】

Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得java代码与html完全分离,利用这个框架开发大型应用变得轻而易举。并且开发的应用很容易维护和升级。Tapestry支持本地化,其错误报告也很详细。Tapestry主要利用javabean和xml技术进行开发。【Spindle:Tapestry辅助开发Eclipse插件】.

Lucene  【Java开源 搜索引擎】

Apache Lucene是一个开放源程序的搜寻器引擎,利用它可以轻易地为Java软件加入全文搜寻功能。Lucene的最主要工作是替文件的每一个字作索引,索引让搜寻的效率比传统的逐字比较大大提高,Lucen提供一组解读,过滤,分析文件,编排和使用索引的API,它的强大之处除了高效和简单外,是最重要的是使使用者可以随时应自已需要自订其功能。

iText  【Java开源 PDF类库】

iText是一个能够快速产生PDF文件的java类库。iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的。它的类库尤其与java Servlet有很好的给合。使用iText与PDF能够使你正确的控制Servlet的输出。

Beanshell  【Java开源 脚本语言】

Beanshell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性。BeanShell执行标准Java语句和表达式,另外包括一些脚本命令和语法。它将脚本化对象看作简单闭包方法(simple method closure)来支持,就如同在Perl和JavaScript中的一样。 它具有以下的一些特点:使用Java反射API以提供Java语句和表达式的实时解释执行;可以透明地访问任何Java对象和API;可以在命令行模式、控制台模式、小程序模式和远程线程服务器模式等四种模式下面运行;与在应用程序中一样,可以在小程序中(Applet)正常运行(无需编译器或者类装载器);非常精简的解释器jar文件大小为175k

OpenCms  【Java开源 内容管理系统(CMS)】

OpenCms是一个J2EE的产品,它是用Java写成的。它和Tomcat捆绑在一起。但是也能够使用ATG Dynamo、WebLogic和WebSphere。OpenCms支持多种RDBMS来保存内容,包括Oracle、SQL Server、Sybase和mySQL。新版本提供了一个新的模板引擎,JSP支持,一种新的连接管理系统,提高了稳定性。

JUnit  【Java开源 Java测试工具】

JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework)。Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。Junit是一套框架,继承TestCase类,就可以用Junit进行自动测试了。

opencrx  【Java开源 ERP与客户关系管理】

opencrx很容易与你现存的系统集成 (ERP, IVR, CTI, ...)是你对你以前投资的最大保护而且openCRX支持大多数通用技术,例如 RMI, CORBA, JMS, SOAP, 以及 JCA; openCRX也包括了支持典型插件的智能前台,例如文档管理,库存跟踪, 设备管理,等. openCRX 可以运行于任意J2EE兼容的应用服务器 (e.g. JBoss, BEA WebLogic or IBM WebSphere) 和主流数据库 (e.g. MaxDB, Firebird, PostgreSQL, MS SQL, Oracle, or IBM DB2). 容易定制 基于 XML 的定制:径直的,迅速的以及可行的(包括多语言特性) 容易扩展写下你自己的工作流,或者发展可扩展的—得益于openCRX的基于组件的体系和像 J2EE,MDA 等的开放标准,这是一个很简单的任务。(摘自http://www.opencrx.com.cn/crx/)

BlueJ  【Java开源 开发工具】

BlueJ是一个专门为入门级教学设计的JavaTM 开发环境。它是由澳大利亚墨尔本Monash大学BlueJ小组设计并开发的。

XWiki  【Java开源 Wiki引擎】

XWiki是一个强大的Java开源的Wiki引擎。它支持一些受欢迎的特性如:
* 内容管理(浏览/编辑/预览/保存),
* 支持附件,
* 版本控制,
* 全文本搜索,
* 权限管理
* 使用Hibernate进行数据存储,
* RSS输出与显示外部的RSS feeds,
* 多语言支持,
* 提供XML/RPC的API,
* WYSIWYG HTML编辑器,
* 导出为PDF
* Groovy脚本支持等等....。

EJBCA  【Java开源 网络服务器】

EJBCA是一个全功能的CA系统软件,它基于J2EE技术,并提供了一个强大的、高性能并基于组件的CA。EJBCA兼具灵活性和平台独立性,能够独立使用,也能和任何J2EE应用程序集成。

Laszlo  【Java开源 XML用户界面工具包】

利用OpenLaszlo免费平台可以快速地,简单地开发漂亮Web 应用程序。这些Web应用程序可以运行在当前任何流行的浏览器与桌面操作系统。它只需要一个XML文件。【IDE4Laszlo:Eclipse下的辅助开发工具】

JXTA  【Java开源 其它开源项目】

 Sun微系统公司公开了旨在建立P2P(Peer to Peer)通用技术基础的JXTA计划。JXTA技术是网络编程和计算的平台,用以解决现代分布计算尤其是点对点(P2P)计算中出现的问题。
 JXTA将建立核心的网络计算技术,提供支持在任何平台、任何地方以及任何时间实现P2P计算的一整套简单、小巧和灵活的机制。JXTA首先将归纳目前P2P的功能特别,而后建立核心的技术来表达目前的P2P计算的局限性。其重点是创建基本的机制,而具体的策略选择权则交给应用的开发者。JXTA将充分利用XML、Java等开放技术,使得UNIX操作系统更强大和灵活,比如利用管道(Pipes)传输Shell命令实现复杂的计算任务。JXTA支持P2P应用的基本功能来建立一个P2P系统,还将努力证实这些可以成为建立更高层功能的基础构造模块。JXTA架构可以分为三个层面:JXTA核心层、JXTA业务层和JXTA应用层。

最近更新


OpenEdit  【Java开源 内容管理系统(CMS)】

OpenEdit包括三大模块Web内容管理,电子商务,博客。Web内容管理包括在线编辑,动态布局,拼写检查(英文), 用户管理,文件管理,版本控制和通告工具。电子商务模块包括在线产品目录管理,购物车,电子付款,产品展示与产品高级搜索(利用Nutch/Lucene的web爬行与搜索功能进行高级搜索所以不需要用数据库的功能). Blog模块包括在线管理,评论,注册和RSS/Atom引擎。 OpenEdit运用到的开源组件有:Velocity,Dom4j,Spring,Lucene。

Role Playing Tools  【Java开源 Java游戏】

这是一个为传统角色扮演游戏提供相关工具的开源项目。当前包括的工具有:MapTool:这是一个可在C/S架构上为多个玩家提供地图与地图数据共享的图形工具。DiceTool:这是一个能够在角色扮演游戏中推测死亡表达式的工具,它还可通过JavaScripts扩展各种计算。TokenTool:方便创建MapTool标记(tokens).

OpenToro  【Java开源 内容管理系统(CMS)】

OpenToro是一个可以让我们以灵活和自动的方式来开发web数据库应用程序的工具.利用OpenToro可以省掉在开发一个Web数据库应用程序时编写JSP与SQL代码这样辛苦乏味的工作.利用它就可以很容易地列出数据库中的表格与其它内容并生成可以新增,修改,删除的数据.OpenToro兼容所有支持SQL-92标准语法的数据库如:MySQL,Oracle,Access,与SQL-Server.

HtmlSave  【Java开源 Eclipse插件】

这是一个可以把Eclipse编辑器中Java源代码或其它语言的源代码存为HTMl格式的插件。

eZing Builder   【Java开源 Eclipse插件】

eZing Builder是一个可以帮助你在很短的时间内开发一个J2EE或MIS应用程序的插件。它类似于PowerBuilder与Visual Web Developer ,但是它使用XQuery来访问XML-DB。

SNMP4J  【Java开源 网络客户端】

SNMP4J是一个用Java来实现SNMP(简单网络管理协议)协议的开源项目.它支持以命令行的形式进行管理与响应。SNMP4J是纯面向对象设计与SNMP++(用C++实现SNMPv1/v2c/v3)相类似。

Sequoia ERP  【Java开源 ERP与客户关系管理】

Sequoia ERP是一个真正的企业级开源ERP解决方案。它提供的模块包括:电子商务应用(e-commerce), POS系统(point of sales),知识管理,存货与仓库管理,客户服务( customer service)等.Sequoia ERP采用Java开发可部署在Linux/Unix 与Windows平台上,并支持当前主流数据库如:MySQL, PostgreSQL,Oracle,Microsoft SQL Server等关系型数据库.

jenia4faces  【Java开源 其它开源项目】

jenia4faces是一个HTML JSF组件包.这个包主要由以下组件组成:Chart- 动态Chart生成。DataTools-DataTable扩展工具。 Dynamic- dhtml text effects。Popup-在html生成弹出式菜单。 Template-简单模板管理器。

Tagit  【Java开源 Web测试】

Tagit是模拟对象(Mock Objects)测试模式的一个实现。它可用于在脱离容器的情况下对自定义JSP标签进行单元测试。

AJAX-JSF Framework  【Java开源 AJAX开发】

这是一个利用AJAX技术并基于JSF来开发轻量级客户端的框架.它设计成可在现有的JSF组件上进行开发并最大限度的满足标准JSF Web流程.

Ditchnet JSP Tabs Taglib  【Java开源 Jsp标签库】

这是一个可用来开发多页选项板(Tabbed Pane)的简单标签。以下是一个Demo:
<tab:tabContainer id="foo-bar-container">

<tab:tabPane id="foo" tabTitle="Foo!">
Foo is cool!
</tab:tabPane>

<tab:tabPane id="bar" tabTitle="Bar!">
<c:out value="Bar is cooler!" />
</tab:tabPane>

</tab:tabContainer>

SWATO  【Java开源 AJAX开发】

SWATO (Shift Web Application TO...)是一组可复用并且结合得很好的Java/JavaScript包.它通过AJAX来轻松转变你web应用程序的交互方式.它带的一些组件包括可以自动补全的文本框架,动态级联下拉列表,动态表单等.

Simple Web Framework  【Java开源 Web框架】

Simple Web Framework (SWF)是一个基于事件的web框架.它很适合于那些想要开发胖客户端Web应用程序但又不想转向JSF的Struts开发人员。SWF跟Struts一样也是构建在Jakarta commons基础之上,但使用一个不同的request processor。SWF事件模型支持基于XmlHttpRequest的事件提交。

Taconite   【Java开源 AJAX开发】

Taconite是一个基于J2EE的框架,可以利用这个框架来简化Ajax开发。Taconite包含一个客户端JavaScript包与一组能自动处理Ajax请求并生成动态内容的自定义JSP标签。

Sequoia  【Java开源 JDBC驱动器】

Sequoia是一个能够为任何数据库提供群集,负载平衡和容错服务的中间件。Sequoia是C-JDBC项目的扩展。

RIFE/Crud  【Java开源 Web框架】

RIFE/Crud是RIFE Web框架的一个扩展模块,它可以用给定的POJOs自动生成CRUD web应用程序。它没有生成任何文件所有的事件都是在运行期进行.利用RIFE提供的 site-structure可以把它与你应用程序的数据流与逻辑流相结合.

Tacos  【Java开源 AJAX开发】

Tacos类包项目为Tapestry Web框架提供一些高性能的组件,同时也为在页面或自己组件中使用的ajax框架(它当前支持的框架主要是dojo但也支持Prototypescript.aculo.usRico)提供服务端Java支持。

JSON-RPC-Java  【Java开源 AJAX开发】

JSON-RPC-Java是一个用Java来实现动态JSON-RPC的框架. 利用它内置的一个轻级量JSON-RPC JavaScripIt客户端,可以让你透明地在JavaScript中调用Java代码。JSON-RPC-Java可运行在Servlet容器中如Tomcat也可以运行在JBoss与其它J2EE应用服务器中因此可以在一个基于JavaScript与DHTML的Web应用程序中利用它来直接调用普通Java方法与EJB方法。JSON:JavaScript Object Notation

Jofti  【Java开源 其它开源项目】

Jofti可对在缓存层中(支持EHCache,JBossCache和OSCache)的对象或在支持Map接口的存储结构中的对象进行索引与搜索。这个框架还为对象在索引中的增删改提供透明的功能同样也为搜索提供易于使用的查询功能。

Yan  【Java开源 IOC容器】

Yan是一个非侵入式的对象反转控制容器(IOC容器)。它通过宣告式的方式把简单的组件组合起来从而构建出任意复杂的组件。这些简单的组件同样也有可能是由其它更简单的组件组合而成。Yan的特点包括开放式的结构,灵活的组件组合,宣告式API和插件式的生命周期管理。Yan对依赖注入的方法没有约束,它可以对商业对象的Public构造方法进行注入,也可以对java bean getter/setter,有规则的java method,任意变量及它们的任意组合进行注入。

Continuum  【Java开源 系统构建】

Continuum可用于Java项目构建的持续集成,使用简单。它内置支持Maven 2,Maven 1, Ant和Shell Scripts.

Winstone  【Java开源 Web服务器】

Winstone是一个Servlet容器,它的目的是提供Servlet功能但没有完全采用J2EE规范.如果有时你要想的只是一个简单的Servlet容器,Winstone是一个最好的解决方案.它支持servlet2.4与JSP2.0规范.

Eclipse 3.1.1 translations  【Java开源 Eclipse插件】

Eclipse 3.1.1和其它Eclipse工具( Visual Editor (VE) , UML2,GEF,EMF / XSD ,WTP等)发布各种语言支持包。其中包括支持中文的NLpack1包。
详细可查看以下网址:
http://eclipse.org/org/press-release/20051012nlscb.html.

下载地址:
Windows 98/ME/2000/XP
NLpack1_FeatureOverlay-eclipse-SDK-3.1.1.zip  
NLpack1-eclipse-SDK-3.1.1a-win32.zip  

Linux (x86/GTK 2)
NLpack1_FeatureOverlay-eclipse-SDK-3.1.1.zip  
NLpack1-eclipse-SDK-3.1.1a-gtk.zip  

Tonic Look & Feel  【Java开源 Swing外观】

这是Swing金属(Metal)外观的免费实现方案.

Commons-IO  【Java开源 Apache其它开源】

Commons IO是Jakarta Commons项目的一个子项目。用来帮助进行IO功能开发.它包含三个主要的领域:Utility classes-提供一些静态方法来完成公共任务.Filters-提供文件过滤器的各种实现.Streams-提供实用的Stream,reader与writer实现.

Datastream Pro  【Java开源 SQL客户端】

Datastream Pro是一个数据库"浏览器"和数据操作工具.它易于使用,可靠,稳定,操作直观。Datastream Pro支持所有兼容JDBC的数据库(已经在Oracle,MySQL,postgreSQL和HSQLDb上测试成功).利用它可以浏览与编辑数据库中的数据,可在一个友好的界面中运行与编辑SQL脚本,可使用查询编辑器来编辑SQL查询,可同时连接到多个数据库和易于使用的连接向导等。

Viento  【Java开源 模板引擎】

Viento是一个用Java开发的模板语言。它在语句构成上很多情形下有点类于Velocity 。

JBoss Microcontainer  【Java开源 IOC容器】

JBoss Microcontainer是一个轻量级IOC容器,它的思想类似于Spring,Pico Container与Plexus。JBoss Microcontainer可被用在任何应用程序中而不需要JBoss应用服务器。 它是JBoss SeamJBoss Embeddable EJB 3.0项目的基础支柱。这里有一篇英文简介文章。

RadRails  【Java开源 Eclipse插件】

RadRails是一个Ruby on Rails框架的IDE。Eclipse更新站点为http://www.radrails.org/update

opencsv  【Java开源 其它开源项目】

opencsv一个简单的CSV解析Java包。

Bugzilla  【Java开源 Bug追踪系统】

Bugzilla是一个Bug追踪系统设计用来帮助你管理软件开发。

WebMacro  【Java开源 模板引擎】

WebMacro是一种Java开源的模板语言。对于表现web页面,它比JSP,PHP,与ASP效率更高。WebMacro是一些大网站后台的页面生成技术。

ECP  【Java开源 Eclipse插件】

Eclipse CORBA Plugin (ECP)提供一个可针对CORBA IDL文件语法进行着色的编辑器。

RDT  【Java开源 Eclipse插件】

RDT是一个用于Ruby开发的Eclipse插件.它提供的功能包括:语法高亮显示,快速语法分析,图形大纲,单元测试,内容提示,源码格式和一个正则表达式插件等。

Commons-Email  【Java开源 Apache其它开源】

Commons-Email的目的是提供一组用于发送Email的API,它基于Java Mail API基础之上并进行了简化。它提供的主要Java类有:SimpleEmail:这个类用于发送简单的文本类型email。MultiPartEmail:这个类允许发送文本消息并附带附件。HtmlEmail:用于发送Html格式的附件并支持内含图片。EmailAttachment:这是一个简单的容器类用于简化附件的处理。

UISpec4J  【Java开源 Java测试工具】

UISpec4J是专门用于Swing应用程序单元测试的一个开源组件,它构建在JUnit测试套件的基础之上.UISpec4J让Java GUI测试变得很简单.它的特殊之处在于它的APIs设计成尽可能地隐藏Swing的复杂性,因此易于测试脚本的读与写.以下这它的简单例子:
 public void testContacts() {
         Table contacts = getMainWindow().getTable();
          contacts.assertContentEquals(new Object[][]{
              {"John", "12", Boolean.FALSE},
              {"Sylvia", "43", Boolean.TRUE},
              {"Bill", "31", Boolean.FALSE}
          });
  }

e-Gen Developer  【Java开源 开发工具】

e-Gen Developer是一个快速应用程序开发(RAD)环境。利用它能够进行Web应用程序的高产开发。e-Gen Developer完全采用Java开发并基于JSF2.8与Struts框架。e-Gen的主要目的是克服IT管理所面对的一些相关挑战如:提高开发效率,减少维护成本与减少训练团队成员所需要的时间。

JavaGroups  【Java开源 网络服务器】

JavaGroups是一个群组通讯工具包。它基于IP组播(multicast),但利用可靠性与群组从属关系对它进行扩展。

UIState  【Java开源 其它开源项目】

UIState是一个非侵入式的用户界面状态(state)管理器用于Java Swing胖客户端应用程序中.UIState允许应用程序恢复它们的GUI状态当应用程序在使用或在多个应用程序之间进行对话时.比如:假如你的应用程序使用JInternalFrame来显示MDI界面的时候,UIState将会为你管理frame的位置和大小.

XINS  【Java开源 其它开源项目】

XINS是一项规范技术用于定义,创建和调用远程APIs。当API规范在XML文档中定义好之后,XINS将会把它们转换成包括客户端与服务端的HTML文档与Java代码.XINS将与复杂的SOAP技术竞争,因为它被设计得具有简单性,可扩缩性与可测试性。简要地说就是:SOA+Java+XML+ 代码生成-复杂性 => XINS。

Fujaba Tool Suite  【Java开源 UML建模】

Fujaba Tool Suite结合UML类图与UML行为视图来提供一个强大,易于使用,而且是整齐均称的系统设计与规范语言. 而且Fujaba Tool Suite还支持从整个系统设计生成Java源代码从完美地实现了一个可执行的模型.同样也支持相反操作,因此源代码可以被解析并被表现在UML中.

EJOE  【Java开源 网络服务器】

EJOE是一个轻量级C/S(client/server)组件用于发送与接收Java对象通过使用外挂式的序列化(serializing)机制.EJOE提供三种功能:1.一个多线程,高性能的网络IO服务器和一个相应的客户端组件。2.序列化所有通过客户端发送的输入对象和由你商业逻辑提供的返回对象。3.提供一个简单,清晰,唯一的接口来把一个对象请求代理集成到你的应用程序中。

JWP  【Java开源 其它开源项目】

Java Web Parts为所有Web应用程序开发者提供了一些可以重复使用和几乎相互独立的Java组件。你可以把这个项目想象成类似于Jakarta Commons项目。JWP包括以下这些组件:AjaxTags一个标签库可以为一个页面轻松地添加AJAX 功能而几乎不用改变现存的JSP代码。DependencyFilter:这个一个简单易用并且是基于declarative(声明)模式的灵活IoC组件。此外它还包括一些过滤器(比如: CompressionFilter,SessionLimiterFilter,
RequestRecorderFilter,AppAvailabilityFilter,
ParameterMungerFilter等),各种用来处理Request, Response与Session的工具类与其它其它一些标签库。

Jencks  【Java开源 其它开源项目】

Jencks是一个轻量级的JCA容器。它可以轻松部署到Spring中以提供消息驱动的POJOs.此外Jencks通过使用类似于JMS,JAX-RPC,JBI与JCA CCI的API来提供对inbound与outbound消息的支持,同时还提供一个基于XA的JDBC连接池机制。

Celtix  【Java开源 企业应用集成(EAI)】

Celtix提供了一个运行期Java企业服务总线和一组可扩展的API.通过使用一个基于标准的,面向服务的体系来简化商业与技术组件的构建,集成和灵活重复使用。

Seam  【Java开源 J2EE框架】

Seam是一个Java EE 5框架。它通过把JSF与EJB3.0组件合并在一起,从而为开发基于Web的企业应用程序提供一个最新的模式。Seam可以让你把EJB组件直接绑定到JSF页面。Seam还可帮助你把jBPM流程定义直接地集成到你的应用程序中。

Saxon  【Java开源 其它开源项目】

Saxon是一个开源的XSLT与XQuery处理器.

AjaxAnywhere  【Java开源 AJAX开发】

AjaxAnywhere被设计成能够把任何一套现存的JSP组件转换成AJAX感知组件而不需要复杂的JavaScript编码.它利用标签把Web页面简单地划分成几个区域,然后使用AjaxAnywhere来刷新那些需要被更新地区域.

Tapestry Palette  【Java开源 Eclipse插件】

Tapestry Palette构建在Spindle插件的基础上.这个插件为Tapestry开发者提供了以下功能:以tree-view的方式来显示在一个项目中所用到的组件.可从tree-view拖放组件到一个页面中.可从远程以拖放的方式下载和安装组件并可直接使用.它还提供一个用于编辑组件参数的property sheet等这里有一个展示该插件功能的Flash.

EasyEclipse  【Java开源 开发工具】

EasyEclipse这是一个把EclipseIDE与一些关键的开源插件分类打包在一起.以使得Eclipse更易于下载,安装,使用.以下是它目前提供的分类组合.

相应的包

版本日期下 载
EasyEclipse CoreEasyEclipse 0.8.1 based on Eclipse 3.1M6 - preview2005/6/23下 载
Extensions-Application ServersJBoss IDE & XDoclets support for EasyEclipse 0.8.0 - version 1.4.12005/6/13下 载
Extensions-Building/DeployingFatJar Jar exporter for EasyEclipse 0.8.0 - version 0.0.182005/6/6下 载
Extensions-Core LibrariesEclipse Tools (EMF, XSD, SDO, GEF, JEM) for EasyEclipse 0.8.02005/6/13下 载
Extensions-DatabasesHibernate Tools for EasyEclipse 0.8.0 - version 3.0 Alpha12005/6/13下 载
Extensions-EditingEclipse Colorer Editor for EasyEclipse 0.8.0 & 0.9.0 - version 0.7.12005/8/8下 载
Extensions-GUI BuildersEclipse Visual Editor for EasyEclipse 0.8.0 - version 1.0.0M42005/6/13下 载
Extensions-Language:AspectJEclipse AspectJ for EasyEclipse 0.8.0 - version 1.2.02005/6/13下 载
Extensions-Language:C/C++Eclipse C/C++ Development Tool for EasyEclipse 0.8.0 - version 3.0.0M62005/6/13下 载
Extensions-MVC Web FrameworksStrutsbox for EasyEclipse 0.8.0 - version 1.0b2005/6/13下 载
Extensions-Plug-in DevelopmentEclipse Plug-in Development Environment for EasyEclipse 0.8.0 - version 3.1M62005/6/13下 载
Extensions-UtilitiesRegex-Regex Tester for EasyEclipse 0.8.0 - version 1.0.02005/6/13下 载
Extensions-Version ControlSubclipse with JavaSVN for EasyEclipse 0.8.0 - versions 0.9.302005/6/13下 载
Extensions-Web DevelopmentEclipse Web Tools for EasyEclipse 0.8.0 - version 1.0.0M42005/6/13下载

JBossProfiler  【Java开源 剖析工具(Profiler)】

JBossProfiler是一个利用JVMPI系统基于log的剖析器。它使用一个C开发的代理从JVM捕获事件并把它们记录到磁盘中。一个运行在JBoss或其它机器上的Web应用程序可被用来分析这些日记。

Yoix  【Java开源 脚本语言】

AT&T实验室研究的Yoix脚本语言是一个多用途的(general-purpose)编程语言.它使用C与Java开发人员所熟悉的的语法和函数.它不是一个面向对象语言,但利用超过150种对象类型来提供对大多数标准Java classe的访问.由于Yoix的解释器(interpreter)完全使用纯Java技术进行构建,因此也能够利用Yoix开发具有跨平台,网络与线程能力的应用程序,还可用于开发GUI应用程序.Yoix语言特性包括指针,寻址,声明,全局与局部变量.

SwiXAT  【Java开源 XML用户界面工具包】

SwiXAT是一个基于Swing的XUL框架用于快速和简化GUI Java应用程序开发.它实现了一个真正的MVC框架,其中利用XML来定义表现层(SwiXml作为XUL引擎),而BeanShell脚本语言用做控制器,并利用JXPath作为view与model之间的绑定机制.

ICM  【Java开源 内容管理系统(CMS)】

ICM(Instant Content Management )是一个开源的Web内容管理系统. 最终用户可以编辑自己的主页以所见即所得的方式.而web设计者有更高级的管理选项并可使用各种标准模板语言来组合一个站点.

Connla  【Java开源 PDF类库】

Connla是一个Java包用于创建可导成TXT,CSV,HTML,XHTML,XML,PDF和XLS等格式的数据集。

Webcockpit  【Java开源 其它开源项目】

Webcockpit是一个web应用程序生成器。它能够生成包含图形(使用JFreeChart 和Cewolf)与HTML表格的完整JSP Web应用程序。图表与表格的内容来自SQL查询。Webcockpit从一个XML配置文件生成JSP页面。

Jen  【Java开源 字节码操作】

Jen为字节码操作与生成提供一组高级API.利用它可以对Java classe进行重命名,把一个数据成员(Field)改成Public访问权限和新增一个构建函数等操作。Jen基于ASM2.1并完全支持Java5注释(annotations)与范型(Generics)。此外它还提供一组额外的工具类用于在运行期生成新的classes。

JyDT  【Java开源 Eclipse插件】

Jython开发工具。

CDT  【Java开源 Eclipse插件】

C/C++在Eclipse平台下的开发工具.它提供的功能包括:C/C++编辑器(一些基本的功能:语法高亮显示,代码编辑等),C/C++调试器,C/C++ Launcher,剖析器,内容提示,Makefile生成器等。

EclipseWork  【Java开源 Eclipse插件】

EclipseWork是一个用于开发WebWork的一个插件.它有很多向导用于创建WebWork Action和利用Hibernate与Prevayler来为应用程序添加增删改查(CRUD)功能.EclipseWork还能生成JSP,Velocity和Freemarker代码.EclipseWork还是一个可扩展的插件你可以编写自己的Eclipse向导而不需要了解Eclipse插件API,你所要做地只是编辑XML和用于生成代码的Velocity模板.EclipseWork将会解析XML并打开这个自定义的向导.在它主页上还提供许多Flash教程。

FacesIDE  【Java开源 Eclipse插件】

FacesIDE是一个用于开发JSF的Eclispe插件.它可以可视化编辑faces-config.xml文件并且提供代码编辑与校验,预览JSF的JSP文件.FacesIDE包含MyFaces来作为JSF的实现.这个插件类似于StrutsIDE.

JDOInstruments  【Java开源 数据库】

JDOInstruments是一个用Java开发的嵌入式面向对象数据库.它还实现了Sun的JDO规范用于Java对象的透明持久化.它可运行在windows2000, windows2003 64bits,和Linux(Fedora Core2)平台上.

EPIC  【Java开源 Eclipse插件】

EPIC是一个开源的Perl开发工具.支持语法高亮显示,快速语法检查,内容帮助,perldoc支持,源码格式,模板支持和一个Perl调试器.

GeoAPI  【Java开源 其它开源项目】

GeoAPI为OpenGIS规范提供一组Java接口。

FINA  【Java开源 其它开源项目】

FINA是一个三层J2EE应用程序用于从一些金融机构(如银行,投资公司等)接收数据,然后把数据存储到DB (Oracle/MSSQL/DB2)数据库中并生成相应的报表. FINA是一个完全可定制的和综合的强大报表设计器.

XSM  【Java开源 内容管理系统(CMS)】

XSM(eXtensible Site Manager)下一代的web网站管理系统。它能够让用户轻松地在线管理它们的网站,并同时在服务器上维护一个静态的网站。

QOLdap  【Java开源 Eclipse插件】

QOLdap是一个Eclipse平台下LDAP目录浏览器.

JDots  【Java开源 其它开源项目】

JDots(Java Dynamic Object Tree System)是一个很小的Java包,它能够让Java开发者构建一棵Java对象树,这些对象之间还可互相通信.一个对象可以发送一个方法调用到它的父节点或子节点对象.参数只能是可包含任何数据格式的TagLists类型.

MiddlegenIDE  【Java开源 Eclipse插件】

MiddlegenIDE是一个Middlegen在Eclipse下的插件,它可生成映射文件,JavaBean源码,配置文件和导入相关的jar.而你所要做的只是配置好数据库连接信息和选择要生成映射文件与Java类的数据库表.MiddlegenIDE当前版本只支持生成Hibernate映射文件与JavaBean源码.

Stripes  【Java开源 Web框架】

Stripes是一个视图框架用于利用最新的Java技术来构建Web应用程序.它具有以下特点:不需要对每一page/action进行映射配置(ActionBeans将自动被发现,它利用注释进行配置),强大的绑定引擎用于构建复杂并脱离请求参数(request parameter)的web对象,易于使用并可本地化的验证与类型转换系统.可重复使用ActionBean作为视图帮助类.支持一个form对应多个事件.透明的文件上传能力.支持持续开发(比如在构思你的ActionBean之前可以先构建与测试JSP)等.

Flow4J  【Java开源 工作流(Workflow)】

Flow4J是一个可在Eclipse平台下以拖放的方式进行工作流建模的插件.一个工作流程可包含许多流程步骤(在该项目中叫作flowlet),然后这些步骤可接连在一起组合成复杂的流程.所有流程将包含以下两种类型的flowlet:Control Flowlets如开始,判断与跳转Flowlets这些将在Eclipse中配置.另一种类型是Task Flowlets:它是一个包含特定任务的Java类,包含的功能可以是任何事件的如EJB调用或JNI调用,这些任务还可用一些脚本语言如Jython,Groovy,JavaScript等来进行开发.当在Eclipse中设计完这些流程之后,所有流程的Java源代码将自动创建.

Crispy  【Java开源 Web服务】

利用Crispy提供的一个统一接口,你可以调用RMI,WebService,REST,XML-RPC,EJB,Burlap,Hessian等其它服务.你不需要知道这些服务是怎样工作的,要调用的服务类型可在properties文件中定义.远程调用就像简单Java对象调用一样,你可以把Crispy集成到一个SOA(Service Oriented Architecture)或RCP(Rich Client Platform)中.

XRadar  【Java开源 项目管理】

这是一个软件开发状况(包括版本,时间,测试,效率,程序代码等等)分析工具. 它会将其绘制成图表来分析,并可以以时间轴输出HTML/SVG报表.

XMoon  【Java开源 Web框架】

XMoon扩展自Jakarta Struts框架用于开发处理基于XML或一些脚本语言(如: BeanShell, JRuby, JudoScript, Jython,Rhino)的Web应用程序.它还提供一个用于展示该框架宠物店Demo.

Voice Tools project  【Java开源 Eclipse插件】

它为JSP/J2EE领域中的Voice Application提供一组基于Eclipse的开发工具.

Red-Piranha  【Java开源 搜索引擎】

Red-Piranha是一个开源搜索系统,它能够真正"学习"你所要查找的是什么.Red-Piranha可作为你桌面系统(Windows,Linux与Mac)的个人搜索引擎,或企业内部网搜索引擎,或为你的网站提供搜索功能,或作为一个P2P搜索引擎,或与wiki结合作为一个知识/文档管理解决方案,或搜索你要的RSS聚合信息,或搜索你公司的系统(包括SAP,Oracle或其它任何Database/Data source),或用于管理PDF,Word和其它文档,或作为一个提供搜索信息的WebService或为你的应用程序(Web,Swing,SWT,Flash,Mozilla-XUL,PHP, Perl或c#/.Net)提供搜索后台等等.

Logisim  【Java开源 其它开源项目】

Logisim是一个教学工具用于设计和模拟数字逻辑电路.

xalan  【Java开源 XML解析】

xalan-java是一套xslt处理器,用来将XML文件转换为HTML,TEXT和XML等其他类型文件格式。支持XSLT1.0和XPATH 1.0版。开发人员可以通过命令行方式或在JAVA APPLET和SERVLET中使用,并可以作为自己开发的应用程序的类库使用。xalan-java实现的是transformation API for XML(TRaX)接口,此接口为jaxp1.2标准中的一部分。

Java SNMP Package  【Java开源 网络客户端】

这是一个实现了SNMP协议的Java包.它提供对基本的SNMP客户端与在SNMP版本1和2中定义的代理操作的支持.这个包提供了一种机制用于取得与设置SNMP对象标识(OID:object identifier)值通过一个简单的通信接口并可用于描述SNMP结构等.

Cobertura  【Java开源 Eclipse插件】

Cobertura是一个基于jcoverage的免费Java工具,它能够显示哪一部分代码被你的测试所覆盖,并可生成HTML或XML报告.

Jeceira  【Java开源 内容管理系统(CMS)】

Jeceira是一个实现了JSR 170规范的内容管理系统.

JBWIKI  【Java开源 Wiki引擎】

一个JBoss实验室项目用于创建符合JSR 168规范的Wiki.它已被用于增强JBoss Portal项目。

Woodstox  【Java开源 XML解析】

Woodstox是一个快速开源且符合StAX(STreaming Api for Xml processing)规范的XML处理器(做为一个处理器意味着它可以处理输入(相当于解析)与输出(相当于写入,序列化))。

Jiplet Container  【Java开源 网络服务器】

Jiplet是Java SIP Servlet的简写,Jiplet Container是一个开源的服务端SIP应用程序容器.Java开发者可以利用Jiplet API来开SIP应用程序并把程序部署到Jiplet容器中.SIP (Session Initiation Protocol)被广范用于通过互联网提供电话服务.这个容器为开发,部署和运行SIP应用程序提供了一个类似于Java Servlet的开发与运行环境.它的许多特性都非常类似于Java Servlet容器包括支持servlet映射(servlet mapping),范围变量(scoped variables),上下文处理(context handling)等. 另外还有一个用于测试SIP应用程序的开源项目SipUnit

Tudu Lists  【Java开源 项目管理】

Tudu Lists是一个日程(todo list)管理J2EE应用程序.它基于JDK5.0,Spring,Hibernate,和DWR AJAX框架.Tudu Lists同样也是一个简单但实效的项目管理工具.

jCookie  【Java开源 其它开源项目】

jCookie是一个免费,开源的Java包用于Java客户端cookie处理.客户端HTTP状态管理(或cookie处理)对于那些需要与Web应用程序如email或在线银行服务进行交互的Java应用程序是非常重要的.

MrPostman  【Java开源 Email客户端】

MrPostman是一个email网关,它使你能够直接从自己喜欢的Email客户端(如: Outlook Express,Thunderbird等)访问Yahoo Mail,Hotmail,gmail(Google mail)和其它webmail服务.它被设计成可扩展,因此可以很容易地添加更多的web mail服务.MrPostman还支持RSS新闻简读.

Deep Network Analyzer (DNA)  【Java开源 网络服务器】

Deep Network Analyzer(DNA)是一个灵活的,可扩展的深度网络分析器(服务器软件)与框架,它可收集和分析网络数据包,网络对话(sessions)与应用层协议(HTTP,DNS,P2P,VoIP等),被动地隔离企业级网络.DNA主要设计用于Internet安全,入侵探测,网络管理,协议与网络分析,信息搜集,网络监测应用程序.

WebHuddle  【Java开源 其它开源项目】

WebHuddle一个小巧(只有100KB),简单(不需要安装-直接运行在浏览器上)并且安全(所有数据通过HTTPS协议加密)的Web based视频会议系统.

AbaGUIBuilder  【Java开源 开发工具】

AbaGUIBuilder是一个用Java开发的可视化Java GUI设计器。它类似于Delphi/VB设计器,能够让应用程序开发者快速设计和创建UI Java应用程序。它当前还包括一套数据库感知组件(aware component).

- 作者: gogomin 2005年12月29日, 星期四 09:32  回复(0) |  引用(0) 加入博采

MFC头文件

Class Header file
CAnimateCtrl afxcmn.h
CArchive afx.h
CArchiveException afx.h
CArray afxtempl.h
CAsyncMonikerFile afxole.h
CAsyncSocket afxsock.h
CBitmap afxwin.h
CBitmapButton afxext.h
CBrush afxwin.h
CButton afxwin.h
CByteArray afxcoll.h
CCachedDataPathProperty afxctl.h
CCheckListBox afxwin.h
CClientDC afxwin.h
CCmdTarget afxwin.h
CCmdUI afxwin.h
CColorDialog afxdlgs.h
CComboBox afxwin.h
CComboBoxEx afxcmn.h
CCommandLineInfo afxwin.h
CCommonDialog afxdlgs.h
CConnectionPoint afxdisp.h
CControlBar afxext.h
CCriticalSection afxmt.h
CCtrlView afxwin.h
CDaoDatabase afxdao.h
CDaoException afxdao.h
CDaoFieldExchange afxdao.h
CDaoQueryDef afxdao.h
CDaoRecordset afxdao.h
CDaoRecordView afxdao.h
CDaoTableDef afxdao.h
CDaoWorkspace afxdao.h
CDatabase afxdb.h
CDataExchange afxwin.h
CDataPathProperty afxctl.h
CDateTimeCtrl afxdtctl.h
CDBException afxdb.h
CDBVariant afxdb.h
CDC afxwin.h
CDHtmlDialog afxdhtml.h
CDialog afxwin.h
CDialogBar afxext.h
CDocItem afxole.h
CDockState afxadv.h
CDocObjectServer afxdocob.h
CDocObjectServerItem afxdocob.h
CDocTemplate afxwin.h
CDocument afxwin.h
CDragListBox afxcmn.h
CDumpContext afx.h
CDWordArray afxcoll.h
CEdit afxwin.h
CEditView afxext.h
CEvent afxmt.h
CException afx.h
CFieldExchange afxdb.h
CFile afx.h
CFileDialog afxdlgs.h
CFileException afx.h
CFileFind afx.h
CFindReplaceDialog afxdlgs.h
CFont afxwin.h
CFontDialog afxdlgs.h
CFontHolder afxctl.h
CFormView afxext.h
CFrameWnd afxwin.h
CFtpConnection afxinet.h
CFtpFileFind afxinet.h
CGdiObject afxwin.h
CGopherConnection afxinet.h
CGopherFile afxinet.h
CGopherFileFind afxinet.h
CGopherLocator afxinet.h
CHeaderCtrl afxcmn.h
CHotKeyCtrl afxcmn.h
CHtmlEditCtrl afxhtml.h
CHtmlEditCtrlBase afxhtml.h
CHtmlEditDoc afxhtml.h
CHtmlEditView afxhtml.h
CHtmlStream afxisapi.h
CHtmlView afxhtml.h
CHttpArgList afxisapi.h
CHttpConnection afxinet.h
CHttpFile afxinet.h
CHttpFilter afxisapi.h
CHttpFilterContext afxisapi.h
CHttpServer afxisapi.h
CHttpServerContext afxisapi.h
CImageList afxcmn.h
CInternetConnection afxinet.h
CInternetException afxinet.h
CInternetFile afxinet.h
CInternetSession afxinet.h
CIPAddressCtrl afxcmn.h
CLinkCtrl afxcmn.h
CList afxtempl.h
CListBox afxwin.h
CListCtrl afxcmn.h
CListView afxcview.h
CLongBinary afxdb_.h
CMap afxtempl.h
CMapPtrToPtr afxcoll.h
CMapPtrToWord afxcoll.h
CMapStringToOb afxcoll.h
CMapStringToPtr afxcoll.h
CMapStringToString afxcoll.h
CMapWordToOb afxcoll.h
CMapWordToPtr afxcoll.h
CMDIChildWnd afxwin.h
CMDIFrameWnd afxwin.h

CMemFile afx.h
CMemoryException afx.h
CMenu afxwin.h
CMetaFileDC afxext.h
CMiniFrameWnd afxwin.h
CMonikerFile afxole.h
CMonthCalCtrl afxdtctl.h
CMultiDocTemplate afxwin.h
CMultiLock afxmt.h
CMultiPageDHtmlDialog afxdhtml.h
CMutex afxmt.h
CNotSupportedException afx.h
CObArray afxcoll.h
CObject afx.h
CObList afxcoll.h
COccManager afxocc.h
COleBusyDialog afxodlgs.h
COleChangeIconDialog afxodlgs.h
COleChangeSourceDialog afxodlgs.h
COleClientItem afxole.h
COleCmdUI afxdocob.h
COleControl afxctl.h
COleControlContainer afxocc.h
COleControlModule afxctl.h
COleControlSite afxocc.h
COleConvertDialog afxodlgs.h
COleCurrency afxdisp.h
COleDataObject afxole.h
COleDataSource afxole.h
COleDBRecordView afxoledb.h
COleDialog afxodlgs.h
COleDispatchDriver afxdisp.h
COleDispatchException afxdisp.h
COleDocObjectItem afxole.h
COleDocument afxole.h
COleDropSource afxole.h
COleDropTarget afxole.h
COleException afxdisp.h
COleInsertDialog afxodlgs.h
COleIPFrameWnd afxole.h
COleLinkingDoc afxole.h
COleLinksDialog afxodlgs.h
COleMessageFilter afxole.h
COleObjectFactory afxdisp.h
COlePasteSpecialDialog afxodlgs.h
COlePropertiesDialog afxodlgs.h
COlePropertyPage afxctl.h
COleResizeBar afxole.h
COleSafeArray afxdisp.h
COleServerDoc afxole.h
COleServerItem afxole.h
COleStreamFile afxole.h
COleTemplateServer afxdisp.h
COleUpdateDialog afxodlgs.h
COleVariant afxdisp.h
CPageSetupDialog afxdlgs.h
CPaintDC afxwin.h
CPalette afxwin.h
CPen afxwin.h
CPictureHolder afxctl.h
CPoint atltypes.h
CPrintDialog afxdlgs.h
CPrintDialogEx afxdlgs.h
CProgressCtrl afxcmn.h
CPropertyPage afxdlgs.h
CPropertySheet afxdlgs.h
CPropExchange afxctl.h
CPtrArray afxcoll.h
CPtrList afxcoll.h
CReBar afxext.h
CReBarCtrl afxcmn.h
CRecentFileList afxadv.h
CRecordset afxdb.h
CRecordView afxdb.h
CRect atltypes.h
CRectTracker afxext.h
CResourceException afxwin.h
CRgn afxwin.h
CRichEditCntrItem afxrich.h
CRichEditCtrl afxcmn.h
CRichEditDoc afxrich.h
CRichEditView afxrich.h
CScrollBar afxwin.h
CScrollView afxwin.h
CSemaphore afxmt.h
CSharedFile afxadv.h
CSingleDocTemplate afxwin.h
CSingleLock afxmt.h
CSize atltypes.h
CSliderCtrl afxcmn.h
CSocket afxsock.h
CSocketFile afxsock.h
CSpinButtonCtrl afxcmn.h
CSplitterWnd afxext.h
CStatic afxwin.h
CStatusBar afxext.h
CStatusBarCtrl afxcmn.h
CStdioFile afx.h
CStringArray afxcoll.h
CStringList afxcoll.h
CSyncObject afxmt.h
CTabCtrl afxcmn.h
CToolBar afxext.h
CToolBarCtrl afxcmn.h
CToolTipCtrl afxcmn.h
CTreeCtrl afxcmn.h
CTreeView afxcview.h
CTypedPtrArray afxtempl.h
CTypedPtrList afxtempl.h
CTypedPtrMap afxtempl.h
CUIntArray afxcoll.h
CUserException afxwin.h
CView afxwin.h
CWaitCursor afxwin.h
CWinApp afxwin.h
CWindowDC afxwin.h
CWinThread afxwin.h
CWnd afxwin.h
CWordArray afxcoll.h

- 作者: gogomin 2005年12月28日, 星期三 10:36  回复(0) |  引用(0) 加入博采

VC++ ADO开发实践之二

一、前言
在上一篇文章《ADO第一次亲密接触》中我们详细介绍了ADO基本的操作方法,在实际的开发过程中我们常常需要存储较大的二进制数据对象,比如:图像、音频文件、或其它二进制数据,这些数据我们称之为二进制大对象BLOB(Binary Large Object),其存取的方式与普通数据有所区别。本文将介绍利用ADO在数据库中存取BLOB数据的具体实现过程,并给出实现图像存取显示的完整示例工程。


二、前期准备
首先我们建立一张名为userinfo的表,包含三个字段:id,username,old,photo,其中photo是一个可以存储二进制数据的字段。
2.1 在SQL SERVER中我们可以在Query Analyzer中直接输入如下语句创建:


CREATE TABLE [dbo].[userphoto] (
 [id] [int] IDENTITY (1, 1) NOT NULL ,
 [username] [varchar] (50) NULL ,
 [old] [int] NULL ,
 [photo] [image] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
其中photo我们定义为image类型的字段。


2.2 在ACCESS中创建的方法如下:
建立一张新表包括id,username,old,photo四个字段,然后打开表,选视图菜单中设计视图,将id设置为自动编号的递增长整型,username为文本,old为数字,photo为OLE对象。
在我们的示例工程中已经包含了一个建立好的ACCESS2000的库,你可以直接拿来使用。


三、具体步骤
3.1 BLOB数据的保存
BLOB类型的数据无法用普通的方式进行存储,我们需要使用AppendChunk函数,AppendChunk包含在Field对象中,原型如下:
HRESULT AppendChunk (const _variant_t & Data );
从函数原型中可以看到关键的问题是我们需把二进制数据赋值给VARIANT类型的变量,下面我们给出具体的代码并作简单的分析:

 

 
///假设m_pBMPBuffer指针指向一块长度为m_nFileLen的二进制数据,并且已经成功打开了记录集对象m_pRecordset///

char  *pBuf = m_pBMPBuffer;
VARIANT  varBLOB;
SAFEARRAY *psa;
SAFEARRAYBOUND rgsabound[1];

m_pRecordset->AddNew();                                              ///添加新记录
m_pRecordset->PutCollect("username",_variant_t("小李"));             ///为新记录填充username字段
m_pRecordset->PutCollect("old",_variant_t((long)28);                 ///填充old字段
if(pBuf)
{   
   rgsabound[0].lLbound = 0;
   rgsabound[0].cElements = m_nFileLen;
   psa = SafeArrayCreate(VT_UI1, 1, rgsabound);                      ///创建SAFEARRAY对象
   for (long i = 0; i < (long)m_nFileLen; i++)
      SafeArrayPutElement (psa, &i, pBuf++);                         ///将pBuf指向的二进制数据保存到SAFEARRAY对象psa中
   varBLOB.vt = VT_ARRAY | VT_UI1;                                   ///将varBLOB的类型设置为BYTE类型的数组
   varBLOB.parray = psa;                                             ///为varBLOB变量赋值
   m_pRecordset->GetFields()->GetItem("photo")->AppendChunk(varBLOB);///加入BLOB类型的数据
}
m_pRecordset->Update();                                              ///保存我们的数据到库中
至此我们的数据已经成功地保存到了数据库中,接下来我们所要做的工作便是将该数据提取出来,让我们继续吧!

3.2 BLOB数据的读取
对应于保存数据时我们所使用的AppendChunk函数,读取数据应该使用GetChunk函数,GetChunk的原型如下:
_variant_t GetChunk (long Length );
给出数据的长度后GetChunk将返回包含数据的VARIANT类型变量,然后我们可以利用SafeArrayAccessData函数得到VARIANT变量中指向数据的char *类型的指针,以方便我们的处理,具体代码如下:

 

long lDataSize = m_pRecordset->GetFields()->GetItem("photo")->ActualSize;///得到数据的长度
if(lDataSize > 0)
{
   _variant_t varBLOB;
   varBLOB = m_pRecordset->GetFields()->GetItem("photo")->GetChunk(lDataSize);
   if(varBLOB.vt == (VT_ARRAY | VT_UI1))                                 ///判断数据类型是否正确
   {
        char *pBuf = NULL;
        SafeArrayAccessData(varBLOB.parray,(void **)&pBuf);              ///得到指向数据的指针
        /*****在这里我们可以对pBuf中的数据进行处理*****/
        SafeArrayUnaccessData (varBLOB.parray);
   }
}
以上我们成功实现了BLOB数据在数据库中的存取,为了让大家有现成的例子可以参考,本文提供了示例工程,在示例工程中我们在数据库中保存图像数据,并可以对这些图像进行浏览、修改,该例子还涉及到如何用char *指向的BMP文件数据创建BITMAP对象然后显示出来。

在Visual C++中如何利用UDL文件来建立ADO连接 
 
    使用通用数据连接文件(*.UDL,以下简称文件)来创建ADO连接,可以和ODBC一样可视化地定义要连接的数据源,从而实现数据访问的透明性。


1.使用UDL文件来创建ADO连接
创建ADO的连接,首先要设置ADO连接对象的ConnectionString属性,该属性提供所要连接的数据库类型、数据所处服务器、要访问的数据库数据库访问的安全认证信息。比较专业的方法是在ConnectionString中直接提供以上信息,下面是访问不同类型数据源设置ConnectionString的标准:
访问ODBC数据
"Provider=MSDASQL;DSN=dsnName;UID=userName;PWD=userPassword;"
访问ORACLE数据库
"Provider=MSDAORA;Data Source=serverName;User ID=userName; Password=userPassword;"
访问MS SQL数据库
"Provider=SQLOLEDB;Data Source=serverName;Initial Catalog=databaseName; User ID=userName;Password=userPassword;"
访问ACCESS 数据库
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=databaseName;User ID=userName;Password=userPassword;"
上述的连接属性设置标准随着数据源的类型不同而变化,软件用户常常不习惯这种设置方式,都希望有可视化的数据源设置方法。为此Microsoft提供了通用数据连接文件(.UDL)来建立和测试ADO连接属性。ADO连接对象可以很方便地使用UDL文件来连接数据源,下面例子使用my_data1.udl来创建ADO连接。
_ConnectionPtr m_pDBConn;
m_pDBConn.CreateInstance(__uuidof(Connection));
m_pDBConn->ConnectionString ="File Name=c:\mydir\my_data1.udl";
m_pDBConn->Open("","","",NULL);
这样一来无论数据源如何变化,在软件中都可以用统一的方法编程。当数据源改变时,只要双击相应的udl文件即可可视化地设置数据源,无需更改软件
因为ADO是COM接口,为了软件的可靠性,打开ADO连接时,可以加入异常处理代码。
try{
m_pDBConn->Open("","","",NULL);
}catch(_com_error &e){
//处理异常的代码
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
m_pDBConn=NULL;
}
因为_ConnectionPtr m_pDBConn是智能指针,应在处理异常代码时将智能指针设为NULL后将自动将引用计数降为0。
如果不出现异常,只要在使用完m_pDBConn,只要引用Close方法即可。
2.创建你所需的UDL文件
在你所想创建UDL文件的目录中单击右键,选择从菜单 新建|Microsoft 数据连接,然后将新创建的UDL文件更改为你所希望的文件名(.UDL扩展名不能改变)。
注:如果操作系统是Window 2000,先创建一个文本文件,再将该文本文件的扩展名改为 "udl"。
然后双击所创建的UDL文件,即可视化地完成数据源的设定。
使用UDL文件必须在系统中先安装Microsoft MDAC,Win 98第二版,Win 2000中都自动包含了该组件,需要该组件最新版本时可以到Microsoft网站去下载

1.引入ADO库文件
使用ADO前必须在工程的stdafx.h文件里用直接引入符号#import引入ADO库文件,
以使编译器能正确编译。代码如下所示:
#import "c:\program files\common files\system\ado\msado15.dll"
no—namespaces rename("EOF" adoEOF")
这行语句声明在工程中使用ADO,但不使用ADO的名字空间,并且为了避免冲突,将EOF改
名为adoEOF。

2.初始化OLE/COM库环境
必须注意的是,ADO库是一组COM动态库,这意味应用程序在调用ADO前,必须初始
化OLE/COM库环境。在MFC应用程序里,一个比较好的方法是在应用程序主类的
InitInstance成员函数里初始化OLE/COM库环境。

  //初始化OLE/COM库环境

  BOOL CADOApp::InitInstance()
  {
if(!AfxOleInit())
{
AfxMessageBox("OLE初始化出错!");
return FALSE;
}
......
}

函数AfxOleInit在每次应用程序启动时初始化OLE/COM库环境。

3.ADO接口简介
ADO库包含三个基本接口:
__ConnectionPtr接口、
__CommandPtr接口和、
__RecordsetPtr接口,

__ConnectionPtr接口返回一个记录集或一个空指针。通常使用它来创建一个数据连接或
执行一条不返回任何结果的SQL语句,如一个存储过程。用__ConnectionPtr接口返回一
个记录集不是一个好的使用方法。通常同CDatabase一样,使用它创建一个数据连接,然
后使用其它对象执行数据输入输出操作。

__CommandPtr接口返回一个记录集。它提供了一种简单的方法来执行返回记录集的存储
过程和SQL语句。在使用__CommandPtr接口时,可以利用全局__ConnectionPtr接口,也
可以在__CommandPtr接口里直接使用连接串。如果只执行一次或几次数据访问操作,后
者是比较好的选择。但如果要频繁访问数据库,并要返回很多记录集,那么,应该使用
全局__ConnectionPtr接口创建一个数据连接,然后使用__CommandPtr接口执行存储过程
和SQL语句。

__RecordsetPtr是一个记录集对象。与以上两种对象相比,它对记录集提供了更多
的控制功能,如记录锁定,游标控制等。同__CommandPtr接口一样,它不一定要使用一
个已经创建的数据连接,可以用一个连接串代替连接指针赋给__RecordsetPtr的
connection成员变量,让它自己创建数据连接。如果要使用多个记录集,最好的方法是
同Command对象一样使用已经创建了数据连接的全局—ConnectionPtr接口,然后使用
__RecordsetPtr执行存储过程和SQL语句。

4.使用__ConnectionPtr接口

__ConnectionPtr是一个连接接口,它类似于CDatabase和CDaoDatabase。首先创建一个
__ConnectionPtr接口实例,接着指向并打开一个ODBC数据源或OLE DB数据提供者
(Provider)。以下代码分别创建一个基于DSN和非DSN的数据连接。

  //使用__ConnectionPtr(基于DSN)

  __ConnectionPtr MyDb;

  MyDb.CreateInstance(__uuidof(Connection));

  MyDb-〉Open("DSN=samp;UID=admin;PWD=admin","","",-1);

  //使用—ConnectionPtr (基于非DSN)

  __ConnectionPtr MyDb;

  MyDb.CreateInstance(__uuidof(Connection));

  MyDb-〉Open("Provider=SQLOLEDB;SERVER=server;DATABASE=samp;UID=admin;

  PWD=admin","","",-1);


5.使用__RecordsetPtr接口
__RecordsetPtr接口的使用方法和CDaoDatabase类似,通过以下代码的比较,你会发现
使用—RecordsetPtr接口非常简单(以下代码使用上面已经创建的数据连接):

  //使用CDaoDatabase执行SQL语句

  CDaoRecordset MySet = new CDaoRecordset(MyDb);

  MySet-〉Open(AFX__DAO__USE__DEFAULT__TYPE,"SELECT  FROM t__samp");

  Now using ADO:

  //使用__RecordsetPtr执行SQL语句

  __RecordsetPtr MySet;

  MySet.CreateInstance(__uuidof(Recordset));

  MySet-〉Open("SELECT  FROM some__table",

  MyDb.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);

  现在我们已经有了一个数据连接和一个记录集,接下来就可以使用数据了。从以下
代码可以看到,使用ADO的__RecordsetPtr接口,就不需要像DAO那样频繁地使用大而复
杂的数据结构VARIANT,并强制转换各种数据类型了,这也是ADO的优点之一。假定程序
有一个名称为m__List的ListBox控件,下面代码我们用__RecordsetPtr接口获取记录集
数据并填充这个ListBox控件:

  //使用ADO访问数据

  __variant__t Holder

  try{while(!MySet-〉adoEOF)

  { Holder = MySet-〉GetCollect("FIELD__1");

  if(Holder.vt!=VT__NULL)

  m__List.AddString((char)__bstr__t(Holder));

  MySet-〉MoveNext();} }

  catch(__com__error  e)

  { CString Error = e-〉ErrorMessage();

   AfxMessageBox(e-〉ErrorMessage());

  } catch(...)

  { MessageBox("ADO发生错误!");}

  必须始终在代码中用try和catch来捕获ADO错误,否则ADO错误会使你的应用程序崩
溃。当ADO发生运行错误时(如数据库不存在),OLE DB数据提供者将自动创建一个
__com__error对象,并将有关错误信息填充到这个对象的成员变量。

6.使用__CommandPtr接口
__CommandPtr接口返回一个Recordset对象,并且提供了更多的记录集控制功能,以下代
码示例使用__CommandPtr接口的方法:

  //使用__CommandPtr接口获取数据

  __CommandPtr pCommand;

  __RecordsetPtr MySet;

  pCommand.CreateInstance(__uuidof(Command));

  pCommand-〉ActiveConnection=MyDb;

  pCommand-〉CommandText="select  from some—table";

  pCommand-〉CommandType=adCmdText;

  pCommand-〉Parameters-〉Refresh();

  MySet=pCommand-〉Execute(NULL,NULL,adCmdUnknown);

  __variant__t TheValue = MySet-〉GetCollect("FIELD__1");

  CString sValue=(char)__bstr__t(TheValue);

7.关于数据类型转换
  由于COM对象是跨平台的,它使用了一种通用的方法来处理各种类型的数据,因此
CString 类和COM对象是不兼容的,我们需要一组API来转换COM对象和C++类型的数
据。__vatiant__t和__bstr__t就是这样两种对象。它们提供了通用的方法转换COM对象
和C++类型的数据。 

- 作者: gogomin 2005年12月26日, 星期一 11:24  回复(0) |  引用(0) 加入博采

VC++ ADO开发实践之一
一、ADO简介
ADO(ActiveX Data Object)是Microsoft
数据库应用程序开发的新接口,是建立在OLE DB之上的高层数据库访问技术,请不必为此担心,即使你对OLE DB,COM不了解也能轻松对付ADO,因为它非常简单易用,甚至比你以往所接触的ODBC API、DAO、RDO都要容易使用,并不失灵活性。本文将详细地介绍在VC下如何使用ADO来进行数据库应用程序开发,并给出示例代码。
本文示例代码

二、基本流程
万事开头难,任何一种新技术对于初学者来说最重要的还是“入门”,掌握其要点。让我们来看看ADO
数据库开发的基本流程吧!
(1)初始化COM库,引入ADO库定义文件
(2)用Connection对象连接
数据库
(3)利用建立好的连接,通过Connection、Command对象执行SQL命令,或利用Recordset对象取得结果记录集进行查询、处理。
(4)使用完毕后关闭连接释放对象。

准备工作:
为了大家都能测试本文提供的例子,我们采用Access数据库,您也可以直接在我们提供的示例代码中找到这个test.mdb。
下面我们将详细介绍上述步骤并给出相关代码。
【1】COM库的初始化
我们可以使用AfxOleInit()来初始化COM库,这项工作通常在CWinApp::InitInstance()的重载函数中完成,请看如下代码:


BOOL CADOTest1App::InitInstance()
  {
  AfxOleInit();
  ......

【2】用#import指令引入ADO类型库
我们在stdafx.h中加入如下语句:(stdafx.h这个文件哪里可以找到?你可以在FileView中的Header Files里找到)

#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
这一语句有何作用呢?其最终作用同我们熟悉的#include类似,编译的时候系统会为我们生成msado15.tlh,ado15.tli两个C++头文件来定义ADO库。

几点说明:
(1) 您的环境中msado15.dll不一定在这个目录下,请按实际情况修改
(2) 在编译的时候肯能会出现如下警告,对此微软在MSDN中作了说明,并建议我们不要理会这个警告。
msado15.tlh(405) : warning C4146: unary minus operator applied to unsigned type, result still unsigned

【3】创建Connection对象并连接数据库
首先我们需要添加一个指向Connection对象的指针:
_ConnectionPtr m_pConnection;
下面的代码演示了如何创建Connection对象实例及如何连接数据库并进行异常捕捉。


BOOL CADOTest1Dlg::OnInitDialog()
  {
  CDialog::OnInitDialog();
  HRESULT hr;
  try
  {
  hr = m_pConnection.CreateInstance("ADODB.Connection");///创建Connection对象
  if(SUCCEEDED(hr))
  {
  hr = m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb","","",adModeUnknown);///连接数据库
  ///上面一句中连接字串中的Provider是针对ACCESS2000环境的,对于ACCESS97,需要改为:Provider=Microsoft.Jet.OLEDB.3.51;
  }
  }
  catch(_com_error e)///捕捉异常
  {
  CString errormessage;
  errormessage.Format("连接数据库失败!\r\n错误信息:%s",e.ErrorMessage());
  AfxMessageBox(errormessage);///显示错误信息
  }

在这段代码中我们是通过Connection对象的Open方法来进行连接数据库的,下面是该方法的原型
HRESULT Connection15::Open ( _bstr_t ConnectionString, _bstr_t UserID, _bstr_t Password, long Options )
ConnectionString为连接字串,UserID是用户名, Password是登陆密码,Options是连接选项,用于指定Connection对象对数据的更新许可权,
Options可以是如下几个常量:
adModeUnknown:缺省。当前的许可权未设置
adModeRead:只读
adModeWrite:只写
adModeReadWrite:可以读写
adModeShareDenyRead:阻止其它Connection对象以读权限打开连接
adModeShareDenyWrite:阻止其它Connection对象以写权限打开连接
adModeShareExclusive:阻止其它Connection对象以读写权限打开连接
adModeShareDenyNone:阻止其它Connection对象以任何权限打开连接

我们给出一些常用的连接方式供大家参考:
(1)通过JET数据库引擎对ACCESS2000数据库的连接

m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\test.mdb","","",adModeUnknown);

(2)通过DSN数据源对任何支持ODBC的数据库进行连接:

m_pConnection->Open("Data Source=adotest;UID=sa;PWD=;","","",adModeUnknown);

(3)不通过DSN对SQL SERVER数据库进行连接:
m_pConnection->Open("driver={SQL Server};Server=127.0.0.1;DATABASE=vckbase;UID=sa;PWD=139","","",adModeUnknown);

其中Server是SQL服务器的名称,DATABASE是库的名称

Connection对象除Open方法外还有许多方法,我们先介绍Connection对象中两个有用的属性ConnectionTimeOut与State
ConnectionTimeOut用来设置连接的超时时间,需要在Open之前调用,例如:
m_pConnection->ConnectionTimeout = 5;///设置超时时间为5秒
m_pConnection->Open("Data Source=adotest;","","",adModeUnknown);


State属性指明当前Connection对象的状态,0表示关闭,1表示已经打开,我们可以通过读取这个属性来作相应的处理,例如:

if(m_pConnection->State)
     m_pConnection->Close(); ///如果已经打开了连接则关闭它


【4】执行SQL命令并取得结果记录集
为了取得结果记录集,我们定义一个指向Recordset对象的指针:_RecordsetPtr m_pRecordset;
并为其创建Recordset对象的实例: m_pRecordset.CreateInstance("ADODB.Recordset");
SQL命令的执行可以采用多种形式,下面我们一进行阐述。

(1)利用Connection对象的Execute方法执行SQL命令
Execute方法的原型如下所示:
_RecordsetPtr Connection15::Execute ( _bstr_t CommandText, VARIANT * RecordsAffected, long Options ) 其中CommandText是命令字串,通常是SQL命令。参数RecordsAffected是操作完成后所影响的行数, 参数Options表示CommandText中内容的类型,Options可以取如下值之一:
adCmdText:表明CommandText是文本命令
adCmdTable:表明CommandText是一个表名
adCmdProc:表明CommandText是一个存储过程
adCmdUnknown:未知

Execute执行完后返回一个指向记录集的指针,下面我们给出具体代码并作说明。
  _variant_t RecordsAffected;
  ///执行SQL命令:CREATE TABLE创建表格users,users包含四个字段:整形ID,字符串username,整形old,日期型birthday
  m_pConnection->Execute("CREATE TABLE users(ID INTEGER,username TEXT,old INTEGER,birthday DATETIME)",&RecordsAffected,adCmdText);
  ///往表格里面添加记录
  m_pConnection->Execute("INSERT INTO users(ID,username,old,birthday) VALUES (1, 'Washington',25,'1970/1/1')",&RecordsAffected,adCmdText);
  ///将所有记录old字段的值加一
  m_pConnection->Execute("UPDATE users SET old = old+1",&RecordsAffected,adCmdText);
  ///执行SQL统计命令得到包含记录条数的记录集
  m_pRecordset =  m_pConnection->Execute("SELECT COUNT(*) FROM users",&RecordsAffected,adCmdText);
  _variant_t vIndex = (long)0;
  _variant_t vCount = m_pRecordset->GetCollect(vIndex);///取得第一个字段的值放入vCount变量
  m_pRecordset->Close();///关闭记录集
  CString message;
  message.Format("共有%d条记录",vCount.lVal);
  AfxMessageBox(message);///显示当前记录条数


(2)利用Command对象来执行SQL命令

  _CommandPtr m_pCommand;
  m_pCommand.CreateInstance("ADODB.Command");
  _variant_t vNULL;
  vNULL.vt = VT_ERROR;
  vNULL.scode = DISP_E_PARAMNOTFOUND;///定义为无参数
  m_pCommand->ActiveConnection = m_pConnection;///非常关键的一句,将建立的连接赋值给它
  m_pCommand->CommandText = "SELECT * FROM users";///命令字串
  m_pRecordset = m_pCommand->Execute(&vNULL,&vNULL,adCmdText);///执行命令,取得记录集

在这段代码中我们只是用Command对象来执行了SELECT查询语句,Command对象在进行存储过程的调用中能真正体现它的作用。下次我们将详细介绍。


(3)直接用Recordset对象进行查询取得记录集
例如

  m_pRecordset->Open("SELECT * FROM users",_variant_t((IDispatch *)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);

Open方法的原型是这样的:
HRESULT Recordset15::Open ( const _variant_t & Source, const _variant_t & ActiveConnection, enum CursorTypeEnum CursorType, enum LockTypeEnum LockType, long Options )
其中:
①Source是数据查询字符串
②ActiveConnection是已经建立好的连接(我们需要用Connection对象指针来构造一个_variant_t对象)
③CursorType光标类型,它可以是以下值之一,请看这个枚举结构:
enum CursorTypeEnum
{
adOpenUnspecified = -1,///不作特别指定
adOpenForwardOnly = 0,///前滚静态光标。这种光标只能向前浏览记录集,比如用MoveNext向前滚动,这种方式可以提高浏览速度。但诸如BookMark,RecordCount,AbsolutePosition,AbsolutePage都不能使用
adOpenKeyset = 1,///采用这种光标的记录集看不到其它用户的新增、删除操作,但对于更新原有记录的操作对你是可见的。
adOpenDynamic = 2,///动态光标。所有数据库的操作都会立即在各用户记录集上反应出来。
adOpenStatic = 3///静态光标。它为你的记录集产生一个静态备份,但其它用户的新增、删除、更新操作对你的记录集来说是不可见的。
};
④LockType锁定类型,它可以是以下值之一,请看如下枚举结构:
enum LockTypeEnum
{
adLockUnspecified = -1,///未指定
adLockReadOnly = 1,///只读记录集
adLockPessimistic = 2,悲观锁定方式。数据在更新时锁定其它所有动作,这是最安全的锁定机制
adLockOptimistic = 3,乐观锁定方式。只有在你调用Update方法时才锁定记录。在此之前仍然可以做数据的更新、插入、删除等动作
adLockBatchOptimistic = 4,乐观分批更新。编辑时记录不会锁定,更改、插入及删除是在批处理模式下完成。
};
⑤Options请参考本文中对Connection对象的Execute方法的介绍

 

【5】记录集的遍历、更新
根据我们刚才通过执行SQL命令建立好的users表,它包含四个字段:ID,username,old,birthday
以下的代码实现:打开记录集,遍历所有记录,删除第一条记录,添加三条记录,移动光标到第二条记录,更改其年龄,保存到数据库


_variant_t vUsername,vBirthday,vID,vOld;
_RecordsetPtr m_pRecordset;
m_pRecordset.CreateInstance("ADODB.Recordset");
m_pRecordset->Open("SELECT * FROM users",_variant_t((IDispatch*)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);
while(!m_pRecordset->adoEOF)///这里为什么是adoEOF而不是EOF呢?还记得rename("EOF","adoEOF")这一句吗?
{
 vID = m_pRecordset->GetCollect(_variant_t((long)0));///取得第1列的值,从0开始计数,你也可以直接给出列的名称,如下一行
 vUsername = m_pRecordset->GetCollect("username");///取得username字段的值
 vOld = m_pRecordset->GetCollect("old");
 vBirthday = m_pRecordset->GetCollect("birthday");
 ///在DEBUG方式下的OUTPUT窗口输出记录集中的记录
 if(vID.vt != VT_NULL && vUsername.vt != VT_NULL && vOld.vt != VT_NULL && vBirthday.vt != VT_NULL)
  TRACE("id:%d,姓名:%s,年龄:%d,生日:%s\r\n",vID.lVal,(LPCTSTR)(_bstr_t)vUsername,vOld.lVal,(LPCTSTR)(_bstr_t)vBirthday);
 m_pRecordset->MoveNext();///移到下一条记录
}
m_pRecordset->MoveFirst();///移到首条记录
m_pRecordset->Delete(adAffectCurrent);///删除当前记录
///添加三条新记录并赋值
for(int i=0;i<3;i++)
{
 m_pRecordset->AddNew();///添加新记录
 m_pRecordset->PutCollect("ID",_variant_t((long)(i+10)));
 m_pRecordset->PutCollect("username",_variant_t("叶利钦"));
 m_pRecordset->PutCollect("old",_variant_t((long)71));
 m_pRecordset->PutCollect("birthday",_variant_t("1930-3-15"));
}
m_pRecordset->Move(1,_variant_t((long)adBookmarkFirst));///从第一条记录往下移动一条记录,即移动到第二条记录处
m_pRecordset->PutCollect(_variant_t("old"),_variant_t((long)45));///修改其年龄
m_pRecordset->Update();///保存到库中

【6】关闭记录集与连接
记录集或连接都可以用Close方法来关闭
      m_pRecordset->Close();///关闭记录集
      m_pConnection->Close();///关闭连接

后记:限于篇幅ADO中的许多内容还没有介绍,下次我们将详细介绍Recordset对象的属性、方法并解决几个关键的技术:绑定方式处理记录集数据、存储过程的调用、事务处理、图象在数据库中的保存与读取、与表格控件的配合使用等。
下次再见吧! 

- 作者: gogomin 2005年12月26日, 星期一 11:22  回复(0) |  引用(0) 加入博采

VC++ ADO开发实践之一
一、ADO简介
ADO(ActiveX Data Object)是Microsoft
数据库应用程序开发的新接口,是建立在OLE DB之上的高层数据库访问技术,请不必为此担心,即使你对OLE DB,COM不了解也能轻松对付ADO,因为它非常简单易用,甚至比你以往所接触的ODBC API、DAO、RDO都要容易使用,并不失灵活性。本文将详细地介绍在VC下如何使用ADO来进行数据库应用程序开发,并给出示例代码。
本文示例代码

二、基本流程
万事开头难,任何一种新技术对于初学者来说最重要的还是“入门”,掌握其要点。让我们来看看ADO
数据库开发的基本流程吧!
(1)初始化COM库,引入ADO库定义文件
(2)用Connection对象连接
数据库
(3)利用建立好的连接,通过Connection、Command对象执行SQL命令,或利用Recordset对象取得结果记录集进行查询、处理。
(4)使用完毕后关闭连接释放对象。

准备工作:
为了大家都能测试本文提供的例子,我们采用Access数据库,您也可以直接在我们提供的示例代码中找到这个test.mdb。
下面我们将详细介绍上述步骤并给出相关代码。
【1】COM库的初始化
我们可以使用AfxOleInit()来初始化COM库,这项工作通常在CWinApp::InitInstance()的重载函数中完成,请看如下代码:


BOOL CADOTest1App::InitInstance()
  {
  AfxOleInit();
  ......

【2】用#import指令引入ADO类型库
我们在stdafx.h中加入如下语句:(stdafx.h这个文件哪里可以找到?你可以在FileView中的Header Files里找到)

#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
这一语句有何作用呢?其最终作用同我们熟悉的#include类似,编译的时候系统会为我们生成msado15.tlh,ado15.tli两个C++头文件来定义ADO库。

几点说明:
(1) 您的环境中msado15.dll不一定在这个目录下,请按实际情况修改
(2) 在编译的时候肯能会出现如下警告,对此微软在MSDN中作了说明,并建议我们不要理会这个警告。
msado15.tlh(405) : warning C4146: unary minus operator applied to unsigned type, result still unsigned

【3】创建Connection对象并连接数据库
首先我们需要添加一个指向Connection对象的指针:
_ConnectionPtr m_pConnection;
下面的代码演示了如何创建Connection对象实例及如何连接数据库并进行异常捕捉。


BOOL CADOTest1Dlg::OnInitDialog()
  {
  CDialog::OnInitDialog();
  HRESULT hr;
  try
  {
  hr = m_pConnection.CreateInstance("ADODB.Connection");///创建Connection对象
  if(SUCCEEDED(hr))
  {
  hr = m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb","","",adModeUnknown);///连接数据库
  ///上面一句中连接字串中的Provider是针对ACCESS2000环境的,对于ACCESS97,需要改为:Provider=Microsoft.Jet.OLEDB.3.51;
  }
  }
  catch(_com_error e)///捕捉异常
  {
  CString errormessage;
  errormessage.Format("连接数据库失败!\r\n错误信息:%s",e.ErrorMessage());
  AfxMessageBox(errormessage);///显示错误信息
  }

在这段代码中我们是通过Connection对象的Open方法来进行连接数据库的,下面是该方法的原型
HRESULT Connection15::Open ( _bstr_t ConnectionString, _bstr_t UserID, _bstr_t Password, long Options )
ConnectionString为连接字串,UserID是用户名, Password是登陆密码,Options是连接选项,用于指定Connection对象对数据的更新许可权,
Options可以是如下几个常量:
adModeUnknown:缺省。当前的许可权未设置
adModeRead:只读
adModeWrite:只写
adModeReadWrite:可以读写
adModeShareDenyRead:阻止其它Connection对象以读权限打开连接
adModeShareDenyWrite:阻止其它Connection对象以写权限打开连接
adModeShareExclusive:阻止其它Connection对象以读写权限打开连接
adModeShareDenyNone:阻止其它Connection对象以任何权限打开连接

我们给出一些常用的连接方式供大家参考:
(1)通过JET数据库引擎对ACCESS2000数据库的连接

m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\test.mdb","","",adModeUnknown);

(2)通过DSN数据源对任何支持ODBC的数据库进行连接:

m_pConnection->Open("Data Source=adotest;UID=sa;PWD=;","","",adModeUnknown);

(3)不通过DSN对SQL SERVER数据库进行连接:
m_pConnection->Open("driver={SQL Server};Server=127.0.0.1;DATABASE=vckbase;UID=sa;PWD=139","","",adModeUnknown);

其中Server是SQL服务器的名称,DATABASE是库的名称

Connection对象除Open方法外还有许多方法,我们先介绍Connection对象中两个有用的属性ConnectionTimeOut与State
ConnectionTimeOut用来设置连接的超时时间,需要在Open之前调用,例如:
m_pConnection->ConnectionTimeout = 5;///设置超时时间为5秒
m_pConnection->Open("Data Source=adotest;","","",adModeUnknown);


State属性指明当前Connection对象的状态,0表示关闭,1表示已经打开,我们可以通过读取这个属性来作相应的处理,例如:

if(m_pConnection->State)
     m_pConnection->Close(); ///如果已经打开了连接则关闭它


【4】执行SQL命令并取得结果记录集
为了取得结果记录集,我们定义一个指向Recordset对象的指针:_RecordsetPtr m_pRecordset;
并为其创建Recordset对象的实例: m_pRecordset.CreateInstance("ADODB.Recordset");
SQL命令的执行可以采用多种形式,下面我们一进行阐述。

(1)利用Connection对象的Execute方法执行SQL命令
Execute方法的原型如下所示:
_RecordsetPtr Connection15::Execute ( _bstr_t CommandText, VARIANT * RecordsAffected, long Options ) 其中CommandText是命令字串,通常是SQL命令。参数RecordsAffected是操作完成后所影响的行数, 参数Options表示CommandText中内容的类型,Options可以取如下值之一:
adCmdText:表明CommandText是文本命令
adCmdTable:表明CommandText是一个表名
adCmdProc:表明CommandText是一个存储过程
adCmdUnknown:未知

Execute执行完后返回一个指向记录集的指针,下面我们给出具体代码并作说明。
  _variant_t RecordsAffected;
  ///执行SQL命令:CREATE TABLE创建表格users,users包含四个字段:整形ID,字符串username,整形old,日期型birthday
  m_pConnection->Execute("CREATE TABLE users(ID INTEGER,username TEXT,old INTEGER,birthday DATETIME)",&RecordsAffected,adCmdText);
  ///往表格里面添加记录
  m_pConnection->Execute("INSERT INTO users(ID,username,old,birthday) VALUES (1, 'Washington',25,'1970/1/1')",&RecordsAffected,adCmdText);
  ///将所有记录old字段的值加一
  m_pConnection->Execute("UPDATE users SET old = old+1",&RecordsAffected,adCmdText);
  ///执行SQL统计命令得到包含记录条数的记录集
  m_pRecordset =  m_pConnection->Execute("SELECT COUNT(*) FROM users",&RecordsAffected,adCmdText);
  _variant_t vIndex = (long)0;
  _variant_t vCount = m_pRecordset->GetCollect(vIndex);///取得第一个字段的值放入vCount变量
  m_pRecordset->Close();///关闭记录集
  CString message;
  message.Format("共有%d条记录",vCount.lVal);
  AfxMessageBox(message);///显示当前记录条数


(2)利用Command对象来执行SQL命令

  _CommandPtr m_pCommand;
  m_pCommand.CreateInstance("ADODB.Command");
  _variant_t vNULL;
  vNULL.vt = VT_ERROR;
  vNULL.scode = DISP_E_PARAMNOTFOUND;///定义为无参数
  m_pCommand->ActiveConnection = m_pConnection;///非常关键的一句,将建立的连接赋值给它
  m_pCommand->CommandText = "SELECT * FROM users";///命令字串
  m_pRecordset = m_pCommand->Execute(&vNULL,&vNULL,adCmdText);///执行命令,取得记录集

在这段代码中我们只是用Command对象来执行了SELECT查询语句,Command对象在进行存储过程的调用中能真正体现它的作用。下次我们将详细介绍。


(3)直接用Recordset对象进行查询取得记录集
例如

  m_pRecordset->Open("SELECT * FROM users",_variant_t((IDispatch *)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);

Open方法的原型是这样的:
HRESULT Recordset15::Open ( const _variant_t & Source, const _variant_t & ActiveConnection, enum CursorTypeEnum CursorType, enum LockTypeEnum LockType, long Options )
其中:
①Source是数据查询字符串
②ActiveConnection是已经建立好的连接(我们需要用Connection对象指针来构造一个_variant_t对象)
③CursorType光标类型,它可以是以下值之一,请看这个枚举结构:
enum CursorTypeEnum
{
adOpenUnspecified = -1,///不作特别指定
adOpenForwardOnly = 0,///前滚静态光标。这种光标只能向前浏览记录集,比如用MoveNext向前滚动,这种方式可以提高浏览速度。但诸如BookMark,RecordCount,AbsolutePosition,AbsolutePage都不能使用
adOpenKeyset = 1,///采用这种光标的记录集看不到其它用户的新增、删除操作,但对于更新原有记录的操作对你是可见的。
adOpenDynamic = 2,///动态光标。所有数据库的操作都会立即在各用户记录集上反应出来。
adOpenStatic = 3///静态光标。它为你的记录集产生一个静态备份,但其它用户的新增、删除、更新操作对你的记录集来说是不可见的。
};
④LockType锁定类型,它可以是以下值之一,请看如下枚举结构:
enum LockTypeEnum
{
adLockUnspecified = -1,///未指定
adLockReadOnly = 1,///只读记录集
adLockPessimistic = 2,悲观锁定方式。数据在更新时锁定其它所有动作,这是最安全的锁定机制
adLockOptimistic = 3,乐观锁定方式。只有在你调用Update方法时才锁定记录。在此之前仍然可以做数据的更新、插入、删除等动作
adLockBatchOptimistic = 4,乐观分批更新。编辑时记录不会锁定,更改、插入及删除是在批处理模式下完成。
};
⑤Options请参考本文中对Connection对象的Execute方法的介绍

 

【5】记录集的遍历、更新
根据我们刚才通过执行SQL命令建立好的users表,它包含四个字段:ID,username,old,birthday
以下的代码实现:打开记录集,遍历所有记录,删除第一条记录,添加三条记录,移动光标到第二条记录,更改其年龄,保存到数据库


_variant_t vUsername,vBirthday,vID,vOld;
_RecordsetPtr m_pRecordset;
m_pRecordset.CreateInstance("ADODB.Recordset");
m_pRecordset->Open("SELECT * FROM users",_variant_t((IDispatch*)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);
while(!m_pRecordset->adoEOF)///这里为什么是adoEOF而不是EOF呢?还记得rename("EOF","adoEOF")这一句吗?
{
 vID = m_pRecordset->GetCollect(_variant_t((long)0));///取得第1列的值,从0开始计数,你也可以直接给出列的名称,如下一行
 vUsername = m_pRecordset->GetCollect("username");///取得username字段的值
 vOld = m_pRecordset->GetCollect("old");
 vBirthday = m_pRecordset->GetCollect("birthday");
 ///在DEBUG方式下的OUTPUT窗口输出记录集中的记录
 if(vID.vt != VT_NULL && vUsername.vt != VT_NULL && vOld.vt != VT_NULL && vBirthday.vt != VT_NULL)
  TRACE("id:%d,姓名:%s,年龄:%d,生日:%s\r\n",vID.lVal,(LPCTSTR)(_bstr_t)vUsername,vOld.lVal,(LPCTSTR)(_bstr_t)vBirthday);
 m_pRecordset->MoveNext();///移到下一条记录
}
m_pRecordset->MoveFirst();///移到首条记录
m_pRecordset->Delete(adAffectCurrent);///删除当前记录
///添加三条新记录并赋值
for(int i=0;i<3;i++)
{
 m_pRecordset->AddNew();///添加新记录
 m_pRecordset->PutCollect("ID",_variant_t((long)(i+10)));
 m_pRecordset->PutCollect("username",_variant_t("叶利钦"));
 m_pRecordset->PutCollect("old",_variant_t((long)71));
 m_pRecordset->PutCollect("birthday",_variant_t("1930-3-15"));
}
m_pRecordset->Move(1,_variant_t((long)adBookmarkFirst));///从第一条记录往下移动一条记录,即移动到第二条记录处
m_pRecordset->PutCollect(_variant_t("old"),_variant_t((long)45));///修改其年龄
m_pRecordset->Update();///保存到库中

【6】关闭记录集与连接
记录集或连接都可以用Close方法来关闭
      m_pRecordset->Close();///关闭记录集
      m_pConnection->Close();///关闭连接

后记:限于篇幅ADO中的许多内容还没有介绍,下次我们将详细介绍Recordset对象的属性、方法并解决几个关键的技术:绑定方式处理记录集数据、存储过程的调用、事务处理、图象在数据库中的保存与读取、与表格控件的配合使用等。
下次再见吧! 

- 作者: gogomin 2005年12月26日, 星期一 11:22  回复(0) |  引用(0) 加入博采