J2ME之谜
第一节 引言 J2ME概述
到目前为止,大部分人都已非常熟悉 Java 2平台,以及 Sun如何把 Java技术分成三个版本
(标准版、袖珍版以及企业版),Sun 在1999年6月时推出了 Java 2袖珍版 (J2ME)来满足消费电
子和嵌入设备的需要。J2ME是为了那些使用有限的能源、有限的网络连接 (经常是无线连接)以及
有限图形用户界面能力的设备开发的。它最初的目标是 16位或 32位处理器,16 MHz时钟频率,
512K或更少内存的设备。乍一看之下, J2ME就像一个没有绑定明显主题的松散的应用程序接口
和技术规范。我们想通过说它不是什么东西的方法来描述它,它不是一组用于台式机 Java应用程
序规范,假如你再观察仔细一些,你会发现所有的 J2ME组件都围绕一个中心,这些中心被称为
configuration(配置 ,Sun的市场营销资料也称它们 design centers,设计中心),它们中间的
每一个都是用于消费电子和嵌入设备的非凡的类。
Connected limited device configuration(有限连接设备配置,简称 CLDC ) 这个配置定义
了 Java应用程序接口以及支持手持设备的技术,就像 Sun的文档中所描述的那样, " devices
that you hold in your hand(你握在手中的设备) " Palm序列手持设备可能是这一领域的设备
的最好的例子,非凡是它有开发 CLDC的功能以及 Palm设备运行期系统可用。
Connected device configuration(连接设备配置 CDC ) 这个配置定义支持象 Sun文档中所
说, " devices that you plug into plug into the wall(你插入墙的设备)的设备的应用程
序接口和技术,这样的设备的一个例子可能就是机顶盒。
这两种配置不同的地方就在于它们应用于的装置的能力, CLDC设备的处理器能力有限 (与台
式机系统比较 ),并且存储器大小一般也只在128 KB到 512 KB之间, 与此同时, CDC系统就不
同了,它可能有 32位或 64位处理器,以及有限的存储容量,不过它的下限也得超过512K。 它遵
循的原则就是,每个不同的能力硬件的配置都将被不同的虚拟机支持。 基于 CDC的系统使用一个
功能强劲的虚拟机,而基于 CLDC系统的使用 KVM (我过会儿会介绍)。
每个配置代表一种低水平的,基本的应用程序接口,在这两个相似基础之上是 profile用于
非凡设备的额外的应用程序接口。
J2ME现在定义两个配置, Connected Device configuration(连接设备配置 CDC )和限制性
更强的 Connected Limited Device Configuration (有限连接设备配置)。 简表的实现是 Java
应用程序接口的一个集合,用于适应被定义配置的应用程序接口提供的服务,简表是一个完整的
运行环境,一个在简表上执行的应用程序不需要额外的支持类。
J2ME没有定义满足这两种配置的标准化用户接口,Sun也承认现在的消费设备多种多样,用户
界面也各不一样,所以定义一个可用于所有用户的界面是一场失败的战争。 J2ME中的用户界面定
义在简表中。
第二节 J2ME的体系结构
现在个人计算机系统的数量和种类已经发展到无法控制的地步,请你想一想,你编写的程序
运行在“信息家电”舞台的情景吧,这些信息家电包括呼叫器,行动电话,像Palm这样的个人数
字助手(PDA),电视机顶盒,POS终端以及其他的消费电子设备。现在全世界上光是手提电话生产
商就有许多,更不用说别的家电设备了,而且每一种家电设备又有不同的特性和界面。所以,你
可以想到, Java应用程序的轻便性以及能够解决开发这么许多不同的设备程序的能力,使大家对
J2ME有很大的期许。当然,为了更好的开发这些信息家电,就要求把Java的精髓压缩进一个非常
小的程序包中,这就是J2ME。
J2ME是一种通过许多部件和规范的技术, 这众多的部件和规范帮助 J2ME来满足这众多的消
费产品的不同的需要。和所有的爪哇程式语言技术一样,在它的核心属于一种虚拟机。 就像使用
所有 Java技术一样,J2ME的核心也在一种虚拟机中。 最初,用于 J2ME应用程序虚拟机的被称
作 Kilobyte virtual machine或简称 KVM。就像它名称的含义, KVM比较小,通常只有 128K或
更少。这比起我们通常了解和使用的 Java 2标准版 Java虚拟机 ( JVM )的 32 MB来说就小得多
了。
用于连接虚拟机的是一系列配置和简表,它们提供了用于特定 J2ME环境的类应用程序接口
(见图二)。 每个配置和简表处理一般或具体的消费产品,配置和简表规范是由多种多样的设备
生产商和用户共同开发并建立的。配置是用于一组通用设备的最小的 Java平台, 经常归为一种
横向的设备分组,相对来说,横向分组设备是那些共享相同的内存安排,通信带宽,能量需求以
及用户能力的设备,一般认为配置能够提供这众多的设备的所有需求。J2ME领域的新的开发者常
常被这些事实困惑的, 事实上, Sun的第一个配置(现在只是一种配置的引用实现 )带有称为
KVM的虚拟机引用实现, KVM满足配置的虚拟机的必要条件。然而, Sun的 KVM也可以被另外一个
虚拟机所代替,现在, 正是因为配置和虚拟机结合得有点紧密,因此导致了这么多的混乱。
另一方面,简表完善了 配置,为某个具体的设备家族或某个具体的工业片段应用程序提供更
高的性能。 换言之, 简表为具体的纵向市场的设备比如说行动电话提供更多的性能。这里的关
键就是 简表必须完善 配置, 没有 配置和虚拟机提供核心类应用程序接口和运行期环境的话,
简表也不会工作。
通常,简表为一种给定的垂直分组设备提供用户界面、输入法、持久性机制。这类 简表被认
为是发展这些设备应用程序的完整的工具包。我们见到最多的应用程序简表的例子就移动电话简
表和个人数字助手(PDA)简表,其他简表为范围宽广的设备提供非常非凡的功能或应用程序可移植
性,这方面的例子就是提供远程方法调用 ( RMI )功能的简表和提供统一银行事务的简表。
虚拟机、 配置、 简表…你是不是已经被搞迷糊了? 假如这样的话,我们就来简化一下
J2ME体系结构吧。 假如你想为小型信息家电编写 Java应用程序的话,你就需要两个前提:一个
配置和至少一个 简表。 现在, 一般是配置捆绑了虚拟机和一套针对你的平台所能够用的横向分
组设备的Java类库。其次,你至少还需要一个 简表来为你的平台提供附加的 Java类,这个 简表
通常会为你的设备提供用户界面、输入和数据库类。有了这两个前提,你就了使用 Java为你的设
备编写应用程序的基本的J2ME环境。
第三节 具体谈谈J2ME配置
J2ME可以在好几个不同的配置中进行配置。 就像先前提到的,每个配置为一组通用设备提供
最小的 Java平台,到目前为止,只有两种配置规范。通过 Java规范定义的这两种配置是
Connected Limited Device Configuration (有限连接设备配置, CLDC )和 Connected Device
Configuration (连接设备配置 CDC )。
CLDC是为使用较小的存储容量的设备设计的 (参见图3 )。 CLDC用于内存在128到 512K之间
的消费电子设备, 这一类别中典型代表的设备包含呼叫器、行动电话、PDA和POS终端;而另一方
面, CDC用于比 PC机小但是具有比 512K内存多的设备,这一类设备包括互联网络电视系统、机
顶盒、POS系统、汽车导航以及娱乐系统。一般来说, CDC使小型设备只要具有少量的资源,至少
比台式机要少的资源就能进行Java编程,而CLDC使小型设备所拥有的资源只要比一张智能卡多一
点就可以进行Java编程了。
除了在容量大小和能力上对虚拟机规定了必要条件,配置还规定了类应用程序接口要包含常见的
java.io、 java.net、 java.util和 java.lang包,配置可能还要包括其他需要的程序包。
CLDC
CLDC起源可以追溯到1999年JavaOne大会上介绍的Sun的第一个袖珍版 Java和第一个 KVM以及
相关的类库,虽然 CLDC和所有的配置都满足成为虚拟机的条件,可它本身还不是虚拟机,CLDC的
引用实现只是包含在当前的分布中的 KVM。
根据规范中所说,运行 CLDC的设备应该有 512K或更少的内存空间、一个有限的电源供给
(通常是使用电池)、有限的或断断续续的网络连接性 ( 9600 bps或更少 )以及多样化的用户界
面甚至没有用户界面。 通常说来,这个配置是为个人化的、移动的、有限连接信息设备而设计,
比如呼叫器、移动电话和 PDA等。
与 J2SE相比, CLDC缺少下列所说的这些特征:
AWT(抽象窗口开发包), Swing或其他图形库
用户定义类装载器
类实例的最终化
弱的引用
RMI
Reflection(映射)
CLDC有四个包: java.lang、 java.util、 java.io和 javax.microedition。 除了
microedition包以外,其他的这几个包都是J2SE包的核心子集,CLDC采用这些J2SE类库,但是把
其中一些在微型设备中用不到类、属性、方法去掉了。因此 CLDC类库有许多细微的差别。 假如
您想研究J2SE和 CLDC类库之间的差别,请参阅相关文档,在此就不具体说明了。
想要理解为什么CLDC去除这么多J2SE中重要的类和特征,请回想一下与 CLDC相关的两条基本
原理。首先,它只有 512K的内存空间, 而像RMI和映射需要的内存太大了。 其次,配置必须满
足为一组通用设备提供最小的 Java平台。 在个人移动信息设备领域中,许多系统都不能支持
J2SE中的众多的高级特征。 例如,许多消费电子产品不能支持浮点数; 因此 Float(浮点类)
和 Double(双精度类)就被删除了。 再看另外一个例子,许多系统没有或不提供访问一个文件
系统的功能或权限。 因此与文件有关的类也被丢弃了。又如,错误处理是一个代价非常高的过程
处理,在许多消费电子设备中,故障恢复是很难的甚至是不可能的。 所以在 CLDC中,许多错误
处理类也被删除了。
java.microedition程序包提供了一个一般的结构来替代许多 J2SE网络输入/输出类。 CLDC
一般连接器结构还定义了一个 Connector类,答应许多不同类型的连接能够使用静态方法,下表
列出使用同一个Connector类创建和打开五种不同类型的连接的方法:
HTTP Connector.open(" http://www.xyz.com ");
套接字 Connector.open("socket://111.222.111.222:9000");
通讯端口 Connector.open("comm:1;baudrate=9600");
数据报 Connector.open("datagram://111.222.111.222");
文件 Connector.open("file:/xyz.dat");
一般连接器结构提供给应用程序开发者一个到通用低水平硬件的简单的映射表。成功执行
open语句将返回一个实现一般连接界面的对象。
CDC
CDC涵盖了个人电脑与有至少 512K内存的小型设备之间的中间地带。现在,这一类设备通常
是共享的、固定的 (不用移动)网络连接信息设备,像电视机机顶盒,网络电视系统、互联网电话
与汽车导航/娱乐系统等等。
首先,CDC基于 J2SE 1.3应用程序接口,包含所有定义在CLDC规范(包括
javax.microedition程序包)中的Java语言应用程序接口。与CLDC相比, CLDC所有缺少的特性和
类在 CDC中都被补齐,包含映射、最终化、所有的错误处理类、浮点数、属性、输入/输出 (
File、 FileInputStream等等 )和弱的引用。 一般说来, CDC中预期的类包括一个J2SE子集和一
个完整的 CLDC超集就像使用所有的配置一样,CDC有基层虚拟机的具体的必要条件。 根据 CDC规
范,基层虚拟机必须提供实现完整的 Java虚拟机的支持 。 假如虚拟机实现有一个用于激活设备
的本地方法的界面,它必须兼容 JNI 1.1版本。 假如虚拟机实现有一个调试界面,它必须兼容
Java虚拟机调试界面 ( JVMDI )规范。 假如虚拟机有一个简表界面,它必须兼容 Java虚拟机简
表界面 ( JVMPI )规范。 可见,为了实现这些功能,CDC肯定会变得很大,就不能称其为K虚拟机
了,因此,我们通常称用于CDC的虚拟机为 CVM,这里的 C代表 compact、connected、
consumer。
第四节 谈谈J2ME简表
虽然配置为一组通用设备提供了最小的 Java平台,但是应用程序开发者感爱好的是为一个个
别的设备生产应用程序,当他们只是使用配置的话,他们编写的应用程序就会有一些欠缺。 配置
必须满足所有的设备的最小的要求, 用户界面、输入机制和数据持久性有高度地设备具体性,每
一种设备都有自己的用户界面、输入机制和数据存储方法,这些往往不在配置所满足的最小要求
的范围之内。
简表为相同消费电子设备的不同的生产商提供了标准化的 Java类库, 事实上,虽然配置规
范的开发由 Sun领导,但是许多简表规范仍将继续由非凡设备的供给商领导。 比如说,
Motorola领导了行动电话和呼叫器简表规范的开发,又如 Palm 领导 PDA简表的开发。
现在,五个已知简表已经有了规范, 记住,每个简表的责任都是为了完善配置的不足,下表
列出了这五个简表:
简 表 完善配置
Mobile information devices profile (MIDP) 移动电话和呼叫器 CLDC
Personal digital assistant profile Palm和Handspring的PDA 设备 CLDC
Foundation profile 用于所有不需要GUI的CDC设备的标准简表 CDC
Personal profile 替代PersonalJava的Foundation完善的简表 CDC
RMI profile 提供RMI的Foundation完善的简表 CDC
现在我想谈一谈另一个Java类库集,它现在差不多可以被认为是另一个简表了。当Sun为Palm
开发第一个KVM时,他们需要一组类来 开发Palm的演示程序。这套类库被封装进 com.sun.kjava
程序包, 在 CLDC早期的开发中,这些类被广泛的使用来测试和演示 J2ME。因为 kjava是唯一的
答应应用程序开发者使用 J2ME和 KVM开发应用程序的类,所以它就被广泛使用了。甚至到了今
天,一个用于 PDA或更非凡一点的 Palm的简表多已经在开发中,许多开发者仍然希望使用 kjava
类来开发 PDA应用程序。尽管 kjava类不被支持,并且仅仅用于设计测试程序或演示程序,并且
它们将被一个即将到来的简表所替代,但是开发者们仍然热衷于使用它来开发。
MIDP
Mobile Information Device Profile(移动信息设备简表 ,简称 MIDP ),第一个实现的简
表,补充了 CLDC并且提供给用程序语义和控件、用户界面、持久存储器、网络和用于移动电话的
计时器、双通道呼叫器和其他无线电设备。 因为 MIDP和 CLDC两者都有引用实现,我们可以使用
一个例程来研究一下这个简表。
下面的例子是一个答应用户输入代表想知道的基金报价的代号的例子。应用程序然后通过
HTTP接到一个金融网站,获得基金报价,把价格储存在一个数据库,然后把价格返回给用户。
// 到如需要的J2ME类
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
// 扩展MIDlet类来构建我们的自定义MIDlet
public class FundTracker extends MIDlet implements
CommandListener {
file://显示治理者变量
private Display display = null;
file://MIDlet的表单变量
private RequestForm reqForm = null;
file://MIDlet构建器
public FundTracker () {
display = Display.getDisplay(this);
reqForm = new RequestForm("Fund Tracker");
reqForm.initForm();
reqForm.setCommandListener(this);
}
file://开始 MIDlet 应用程序
protected void startApp() {
display.setCurrent(reqForm);
}
file://暂停 Midlet
protected void pauseApp() {
}
file://销毁Midlet
protected void destroyApp(boolean unconditional) {
}
file://通过监听者响应命令
public void commandAction(Command c, Displayable s) {
if (c == reqForm.getExitCommand()) {
destroyApp(false);
notifyDestroyed();
return;
}
if ((c == reqForm.getGetCommand()) &&
(reqForm.getSymField().getString().length() > 0)) {
getAndDisplayQuote();
} else
{
reqForm.getMsgString().setText("Symbol required");
}
}
file://储存由#分开的成对的基金字符串和报价字符串
private void storeQuote (String fund, String newQuote) {
file://数据库变量
RecordStore quoteDB = null;
try {
quoteDB = RecordStore.openRecordStore(
"FundQuotes", true);
byte[] data = (fund + "#" + newQuote).getBytes();
int size = data.length;
quoteDB.addRecord(data, 0, size);
quoteDB.closeRecordStore();
}
catch (Exception recordException) {
System.out.println("Unable to store quote and/or
use Fund Quote database.");
}
}
file://通过QuoteService类取回提交的代号表示的基金报价
private void getAndDisplayQuote(){
String fundSymbol = reqForm.getSymField().getString();
if (fundSymbol.length() > 0) {
String theQuote = QuoteService.getQuote(fundSymbol);
if (theQuote != null) {
storeQuote(fundSymbol, theQuote);
reqForm.getMsgString().setText(theQuote);
}
else
reqForm.getMsgString().setText("No quote" +
´´