Classc=class.forName("Person");
Personp=(Person)c.newInstance();
System。out.println("...justcreateda"+c.getName();
· 清单2:一个简单的Class.forName()例子
然而,此处还有一些问题。由于对某些特定的类来说,forName()函数需要调用参数为void的构造函数,所以不能将RecordSet变量直接传递给构造函数。在这里,我们需要一个初始化函数,把从数据库中抽取出的记录作为RESULTSET参数,将其值赋予对象的数据元素。一个好的方法是引入超级类,并将其作为所有数据库表相关类的通用父类。实际上,这个超级类在数据库查询中充当着重要的角色,我们将在下面展示这一点。
查询数据库利用上面的方法可以由记录生成对象,但是你仍然得用SQL语句来查询数据库,这需要对数据库结构有深入的了解。这还是没有解决问题,虽然我们能够自动地匹配数据库表和类的名字,但是还是必须手工编写SQL语句。这就是说每次修改数据库结构后,将不得不手工编辑这些查询语句。不过,我们仍然可以利用前文所述的方法来越过这个障碍。通常而言,查询关系数据库时,你将会用到属于主键或索引的字段名和值。一言弊之,如果某人向你提供了适当的字段名和字段值
,你就可以从相应的数据库中抽取符合要求的记录(或字段)。而DatabaseMetaData对象不但可以被用于检索一系列的表名(见上所述),而且可以获得一系列的主键及索引字段。上面的问题由此可以迎刃而解。
通过填入一系列适当的(字段名,字段值)对,可以利用相对而言少得多的代码实现对关系数据库的查询。你可以将对子中的所有字段名和数据库中的主健及索引字段相匹配。每当你找到了名字列表中相应的主健或索引字段,可以根据相应的数值来生成一个SQL语句,执行它来获取RecordSet,并通过Class.forName()构造机
制将结果转化为对象。实现这一想法要求可以以(名,值)对的方式对与数据库表相关的每个类的数据元素进行存取。但是这种方法只有通过上节所述的通用父类才能趋于完美。清单3和4利用伪码表示了这一方法。
Openthedatabaseconnection
Retrievealistofuserdefinedtables
foreachtable
{
Checkwherethereisacorrespondingclassfile
if(itisavailabe)
{
loadtheclassfile
Retrievelistsofkeyfieldsandindecesforthistable
Storetheselistsinhashtablesforeasyaccess
}
elsethrowanexception
}
· 清单3:初始化数据库连接的伪码
TakeanobjectAcontainingaseriesof(name,value)pairs
foreachtableT
{
foreach(name,value)pair
{
if(namematchesprimary_key_fieldorindex_field)
storearefrencetobothnameandvalue
}
ifallkey_fieldswerefound
createaquerystringusingkeynamesandvalues
elseifallindex_fieldswerefound
createaquerystringusingindexnamesandvalues
executethequerytoobtainaResultSet
ForeachrecordintheResultSet
{
CreateanobjectoftheclassassociatedwithtableT
initializetheobjectusingtherecord''scontents
Addtheobjecttotheresults,e。g。,attachittoA
}
}
· 清单4:描述数据库查询的伪码
Java镜像和JavabeansJava1.1开发套件(JDK)的引入,为我们带来了许多强大的新性能,例如全新的用户界面接口类。有两个新的JDKAPI尤其值得注意:镜像机制(java.lang.reflect包)和JavaBeans组件的应用程序接口(java.beans包)。这两个API将会帮助我们创建高明的数据库类,使我们可以利用有关类的meta-信息,以此来解决开发通用数据库类中的问题。
拥有forName()和newInstance()方法的Class类,仅仅是镜象(reflection)功能的一个简单例子。真正重要的是,forName()字符串参数不必须是源程序中出现的字符串。只要给出一个名字(这个名字可从任何地方取来),你就可以载入并实例化任何一个类。对于我们的数据库类,我们可以直接从数据库自身的表名中得到类名。这就是说,与数据库表相关的Java类名并不需要出现在源程序中。相应地,当表名改变或某个表被加入到数据库中时,不需要修改源码,只要确信带有新名字的类已存在你的系统中。
镜像类意味着可以在实时运行中获取、存储和处理Java程序中的类信息。它们的实例能够象任何Java对象一样被运用,你可以象修改字符串和整数一样,去修改类、数据类型、返回类型、方法参照和参数。在源程序级,这个镜像的概念看起来并没有什么价值——因为可以应用你自己的编码直接存取你所需要的有关类、方法及参数的所有信息。但是,镜像(reflection)将会在java的编译文件中发挥作用。JavaBeansAPI的作用是:通过应用程序的构造机制利用来自于全然不同的开发者或产商所编写的类。
JavaBeans规范为类成员的名字制定一系列的条例。以确保方法函数的名字能系统地描述它们的功能。任何一个符合规则的Java类都可以被一个Bean的内化实例(通过镜像)检查,以揭示其行为的重要特征——诸如对于什么样的事件类将有所响应,以及该类将会产生什么样的事件等等。任何符合这些规范的类都是高效的Bean,因而是一个组件。在理论上,这意味着你可以从各种来源收集一系列beans,当需要它们时可以将其其实时地绑在一起。一个Bean的例子
在下面一个名为Translation的Bean中,有一个构造函数和两个方法来操作一个名为“language”的属性。这里我想强调的是,既然你可以通过检查一个类的代码来了解它的构造函数、方法及属性,那么Bean的内化器(Introspector)也能做到。
publicclassTranslationextendsObject
{
intlanguage;
publictranslation()
{
}
publicintgetlanguage()
{
return(language);
}
publicvoidsetLanguage(intlanguage)
{
this。language=language;
}
}
· 清单5:一个非常简单的Bean
一个BeanIntrospector能够提供许多数组的PropertyDescriptor实例,这些实例包含所有Bean的属性的类型信息,即例子中由get/set方法所定义的类型。你可以调用这些方法(利用reflection)来读或写这些属性。
镜像机制(reflectionfacilities)为我们检查原本松散的类和数据库表的完整性提供了的更好方法。实际上,仅仅通过类名和一个表匹配并不一定能够保证一些类内部的一致性。一个与表相关的类显然应当具备存储数据库表中所有字段的数据元素。一个类可能有适当的名字,但其初始化代码可能会省略。它可能只有一个正
确的名字,而其数据成员可能有不同的名字或者是不同的类型。使用JDBC的DatabaseMetaData及镜像机制可以检查它们是否完全匹配!引用一些JDBC调用去获得现实中必须的数据库信息,通过正确的名字去检查你系统中的类,并且通过镜像去比较表和类的属性,这实实在在是一块香饼!结论和启示JDBC,镜像和JavaBeans三者的结合,能够方便地从关系数据库中存取记录并利用记录来初始化组件(不仅仅是对象)。
为了实现上述操作,无需修改你的数据库,只需确认你的类符合Bean规范,并使类属性和表字段相互匹配。Beans还有其它一些简单的技巧,可使编程更加有趣。Be
ans能够提供自己的用户界面组件,并且Beans规范还包括一个名为Customizers的东西。你可以引入另外的类专门地去察看、编辑和自行定制一个Bean类的实例。(关于定制Beans,请参看下一期《定制你的Java》
· 总之
我们可以为数据库类编写自行定义的类,应用程序能够从关系数据库中抽取数据,通过实例化某个类得到新的实例,并引入相关的图形用户界面(GUI)组件来查看和编辑数据。所有这些都由通用代码完成,因而能够处理任何数据库。利用Java编写的、功能齐全的数据库查看/编辑器正迎我们而来。
张智雄编译
文章来源于领测软件测试网 https://www.ltesting.net/