CLDC标准为了能够涵盖尽可能多的设备,其类库只包含了最小的Java平台特性和API。面对严格的内存限制和当前各种各样的小型设备,CLDC不可能覆盖全部的这些设备。因此在CLDC的规范中,不可避免的会造成对某些设备要求过高或是对另一些设备要求又太低的现象。
为了确保与其他Java平台的兼容性,绝大多数的CLDC类库是从J2SE和J2EE中继承的,是J2SE和J2EE的子集。由于目标设备的特殊性,CLDC类库在安全、输入/输出、用户界面、网络和存储管理等方面没有全部使用J2SE的实现;其中的部分类库CLDC进行了重写,如网络连接。
CLDC的类库可以分为两种:一种是从J2SE标准类库中继承的;另一种是专门为CLDC设计的(这部分类也可以被映射到J2SE中)。
对于第一种CLDC类库,包括了J2SE的3个最核心的包java.io、java.lang和java.util。而且这3个包和J2SE相比,也只是J2SE相应包的一个很小的子集。例如java.util的类与接口由J2SE中的53个减少到10个。
对于后一种CLDC类库,只有描述标准连接框架的javax.microedition.io包,和MIDP中定义的包一起放于javax.microedition包中。
1 java.lang包
java.lang包包含了Java语言API的核心部分继承下来的类,但是CLDC只继承了J2SE中一半的类,而且一些类中的接口并没有完全实现。这主要表现在
1)绝大部分的虚拟机不支持错误类和部分异常类被去掉了。
2)不支持Float和Double数据类型及其相应的类
3)ClassLoader、SecurityManager等CLDC规范上没有说明必须支持的类也不在此包中。
下表给出了CLDC 的java.lang包中的类及类的继承关系。
CLDC1.0 java.lang包中的类及类的继承关系
java.lang.Object类:
Object类中需要注意的有以下两点:
1. 没有finalize( )方法。
2. 没有接口类java.lang.Cloneable,所有CLDC虚拟机的对象都没有默认的clone()方法。
数据类:
在前面已经提到过多次,CLDC不支持浮点数据类型,核心库中的java.lang.Floart类和java.lang.Double类以及其他类中与浮点数据相关的方法均不予支持。CLDC支持的数据类型有:Boolean、Byte、Char、Integer、Long、Short和String。
需要注意的是:
1. java.lang.Number不在核心库中,java.lang.Byte等基本数据类直接从java.lang.Object类继承。
2.接口类java.lang.Comparable没有出现在CLDC规范中,所以数据对象之间不能像J2SE那样直接调用compareTo()方法比较。
3. String类与J2SE相比变化较大,其中去掉了compareToIgnoreCase()、copyValueOf()、equalsIgnoreCase()、split()、match()和intern()等方法;其余部分方法进行了缩减。
4. java.lang.Math类相对J2SE功能要小很多,只提供了和int、long有关的三组操作。
Class类:
forName()方法和newInstance()方法仍然可以用,用来获得未知的class对象。getResourceAsStream(String name)方法可以找到指定名字的资源,并以InputStream的形式获得。该方法常用于读取本地MIDlet JAR包中图片或者文本文件或是某个Java包。参数——name可以是绝对路径(以“/”开头,如/com/sun/MIDlet1/resources/pic.png),也可以是相对于当前MIDlet目录下的相对路径(如resources/pic.png)。
System类和Runtime类:
Runtime类和System类实现设备底层的操作,这些操作通常会涉及底层。考虑到底层相关的属性和虚拟机性能等约束的原因,这两个类都仅仅包含了J2SE有限的几个方法。
1. 在CLDC的简表MIDP中定义一些J2SE中没有的系统属性。通过getProperty()方法可以获得指定的属性值(String config = System.getProperty("microedition.configuration"))然而,CLDC没有实现J2SE中的类java.util.Properties。这就意味着,不能通过getProperties( )方法获得全部系统属性列表。而且应用程序不能利用setProperty()或setProperties()方法定义自己的属性。原有的通过JNI连接native code的方法由于JNI的不支持也都被省掉了。其中,如果支持多个简表,中间用空格区分。
名称 | 含义 | 值 |
microedition.platform | 主机平台或设备的名称 | 默认值为null |
microedition.encoding | 默认编码格式 | 默认值为“ISO8859_1” |
microedition.configuration | 所支持的配置版本 | 默认值为“CLDC-1.0” |
microedition.profiles | 所支持的简表名称 | 默认值为null |
系统属性列表
2. J2SE中最常用的常量err和out仍然被System类保留了,但是常量in被删掉了。所以CLDC中没有标准的输入数据对象了。
3. 还要注意的是停止虚拟机运行的exit()方法。CLDC虽然允许MIDlet(应用程序)直接调用并执行该方法,但是MIDlet会收到SecurityException的异常。
4. 由于设备的内存限制,J2ME中gc()的使用率比J2SE高出很多,但是其本质和J2SE并没有区别,垃圾收集的工作全权由系统负责。另外在J2ME中使用gc()时要找准时机。
Thread类和Throwable类:
CLDC要求虚拟机必须支持多线程,即使底层平台并不支持。J2SE中对多线程的定义——Tread类、关键字synchronized、对象的wait()、notify()和notifyAll()等方法都纳入了CLDC规范。然而,CLDC并不支持线程组,也没有提供TreadGroup类。
还有一些和J2SE的Tread类不同的地方是:
1. 线程不能自己取名,即getName()和setName()方法在CLDC中不予提供。
2. 删除了resume()、suspend()和stop()方法。这些方法在J2SE中已经是不在推荐使用的了(depredated)。
3. 线程对象没有destory()、interrupt()和isInterrupted()方法。因此,CLDC的线程必须由程序员自己控制结束(通常用boolean变量+循环来控制),如:
Public void run() {
While (!threadStopped){
//the actions in the thread
}
}
4. dumpStack()方法被去掉了,类似的操作会抛出异常。
错误和异常类:
从类图表2.3中可以看到,CLDC中大多数的异常类是在java.lang包中定义的,而错误类仅仅3个。这些错误类和异常类都和J2SE中的相同。特别需要注意的是Throwable类中的printStack()方法。该方法的输出格式由虚拟机的实现自行规定;特别是在Sun的实现KVM中,该方法仅仅会把异常的名字打印出来。
2 java.util包
CLDC的java.util包主要包括了集合类和时间、日期的相关的12个类。其中的10个类是从J2SE中继承来的;Timer和TimerTask类是MIDP增加的类。下表给出了CLDC 的java.lang包中的类及类的继承关系。
CLDC 的java.lang包中的类及类的继承关系
集合类:
CLDC规范中包含了4个集合类:Hashtable、Stack、Vector和Enumeration。和J2SE相比,它们的功能被大大削减了,这点从继承关系上就可以看出:J2SE中的集合框架被取消了,它们都直接从java.lang.Object类直接继承。
Date类:
CLDC的Date类比J2SE要简单的多。Deprecated 构造函数和方法都被除去了;多个Date对象的比较方法只能用equals()来进行。因此,我们不能直接通过Date对象获得时间(日期)的一部分,如年、月、日等。这些功能仅在Calendar类中有定义。
TimeZone类:
CLDC规范规定设备只需要支持其默认的GMT时区。在KVM的实现中,支持GMT和UTC两种时区表示。
Calendar类:
Calendar类是抽象类,没有直接的构造方法,要构造一个默认的Calendar对象必须调用静态方法getInstance()。下面列出了Calendar对象不同的构造方法:
Calendar cal = Calendar.getInstance();
TimeZone timezone = new TimeZone();
Calendar cal = Calendar.getInstance(timezone);
Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
在Date类的介绍中提到过,Date类中不能提取时间的一部分,而和Calendar类一起使用就可以很容易的完成Date对象的分解和加减等的运算。
Calendar类不能以字符串的形式返回年月日,因为CLDC没有包含java.text包。在KVM的实现中,只能通过toString()方法获得形如Sat, 9 Apr 2005 12:00:00 UTC的字符串。不同的虚拟机的实现可能会返回不同格式的字符串。
Timer和TimerTask类:
MIDP通过Timer和TimerTask类提供了一种实现简单的多任务调度执行的方法,调度由一个专门的后台线程完成。其中,TimerTask 是用户定义的需要被调度的所有任务的抽象基类。Timer 类在任务执行的时候负责创建和调度执行线程。这些调度由Timer类的schedule()和scheduleAtFixedRate()方法来完成,而run() 方法用来执行各个任务。此外每个 正在执行的任务必须能够尽快的终止,因为每个 Timer 对象在同一时间只能执行一个任务。
schedule()和scheduleAtFixedRate()方法都可以通过指定任务的开始时间、延迟时间或者任务的持续时间来调度任务。两者的区别在于,当某个任务因为某种原因出现一段时间的延迟后,之后所有由schedule()方法调度的任务都会顺延;而之后所有由scheduleAtFixedRate()方法调度的任务会自动根据一个固定的频率来调整。也就是说,在相同的一段时间内,如果用schedule()方法执行10次的任务,用scheduleAtFixedRate()方法调度可能会执行9次或是11次。
另外,TimerTask类提供了cancel()方法用于在任务执行的过程当中强行终止任务,该方法是从Runnable接口类继承来的。一旦终止了该任务,那么它将退出任务调度。在任何时间调用cancel()方法都是有效的,即使该任务还一次都没有执行过。
3 java.io包
CLDC的java.io包是J2SE的子集,只提供了相当有限的8位输入/输出功能。而且,一些抽象类,像FilerInputStream等,也被省掉了,原先从这些抽象类继承的类直接从它们的父类InputStream和OutputStream继承。这里只表2.5给出了CLDC中java.io包中的类及类的继承关系。
CLDC1.0 java.io包中的类及类的继承关系
对于CLDC,InputStream和OutputStream类是读写数据的唯一的途径。无论是本地文件或是网络连接的读写都要通过这两个类来完成。一个典型的例子就是:MIDlet提供了本地存储方式——RecordStore,它以字节数组的形式存储内容。MIDlet需要把要存的内容转换成ByteArrayInputStream或是DataInputStream对象格式来储存。同样的,调用在javax.microedition.rms中操作RecordStore的API所返回的也是ByteArrayOutputStream或是DataOutputStream对象。
由于CLDC不支持浮点数据,因此DataInput和DataOutput接口类只提供了对boolean、char、int、long和short型数据的读写操作。
DataInputStream、DataOutputStream类在J2SE中是从FilerInputStream和FilerOutputStream继承来的。CLDC中FilerInputStream和FilerOutputStream被省掉了,所以DataInputStream和DataOutputStream直接成为了InputStream和OutputStream的子类。DataInputStream类不能直接构造,要通过其他方法获得。例如,通过javax.microedition.io.Connector中的openDataInputStream方法,这是CLDC通用连接框架(GCF)中从网络获取数据流的最长用的方法。而DataOutputStream类可以直接构造,也可以通过如javax.microedition.io.Connector中的openDataOutputStream等方法获得。
Reader和Writer类从java.lang.Object继承,基本上与J2SE区别不大。它们的作用是提供有限的国际化支持。J2SE中这是通过Reader和Writer对象实现的,而CLDC中使用了InputStream和OutputStream来完成同样的功能。
InputStreamReader类用于把8位的输入数据流转化成unicode码。然而,在CLDC规范中仅要求设备支持自身默认的编码格式,其他的编码格式可以有选择的支持。CLDC也不提供可以在运行时把应用程序的编码自动转成设备默认编码格式的功能。系统支持的编码格式可以从系统属性microedition.encoding中获得。如果系统不支持指定的编码,会抛出UnsupportedEncodingException异常。需要注意的是,InputStreamReader类支持InputStream类中的mark()和reset()方法;而J2SE中的getEncoding()方法被去掉了。
和InputStreamReader类似,OutputStreamWriter类中也去掉了J2SE中的getEncoding()方法。
PrintStream类直接从OutputStream类继承,不支持浮点数据的打印。同时需要注意的是,print()和println()不会抛IOException,需要用checkErro()方法查看错误状态。
CLDC的java.io包提供的IOException及其4个子类都和J2SE相同,这里就不再说明了。
4 javax.microedition.io包
CLDC1.0 javax.microedtion.io包中的类及类的继承关系
javax.microedtion.io包定义了GCF中的类和接口,其中最关键的是Connector类和Connection接口。Connector类中定义了静态方法生成特定类型的Connection,利用这个Connection可以访问网络和各种其他设备。关于GCF的特点和用法将在本教程的第七章联网部分做详细介绍。