兼容性
语言支持
GWT 支持大多数核心 Java 语言语法和语义,但有一些区别需要注意。
GWT 2.8+ 支持 Java 8 语法。(以前的版本支持较低版本的 Java,有关更多信息,请参阅发行说明。)
重要的是要记住,GWT 应用程序的目标语言最终是 JavaScript,因此在开发模式和生产模式(以前分别称为托管模式和Web 模式)下运行应用程序之间存在一些差异。
内在类型:基本类型(
boolean
、byte
、char
、short
、int
、long
、float
和double
)、Object
、String
、数组、用户定义的类等都受支持,但有一些注意事项。- 算术运算:在 JavaScript 中,唯一可用的数字类型是 64 位浮点数。因此,在生产模式下,所有 Java 基本数字类型(除了 long,见下文)都像在 double 上一样实现。主要而言,这意味着整数数据类型(
byte
、char
、short
、int
)的溢出不会像 Java 指定的那样包装基础值。相反,结果值将超出该数据类型的合法范围。对float
的操作将作为double
执行,并导致比预期更多的精度。整数除法被实现为显式舍入到正确的值。 long
:JavaScript 没有 64 位整数类型,因此long
需要特殊考虑。在 GWT 1.5 之前,long
类型只是映射到 64 位 JavaScript 浮点数值的整数范围,从而使long
变量的实际范围小于完整的 64 位。从 GWT 1.5 开始,long
基本类型被模拟为一对 32 位整数,并在整个 64 位范围内可靠地工作。溢出被模拟以匹配预期的行为。这里有两个注意事项。大量使用long
操作将由于底层模拟而对性能产生影响。此外,long
基本类型不能在JSNI 代码中使用,因为它们不是本机 JavaScript 数字类型。
- 算术运算:在 JavaScript 中,唯一可用的数字类型是 64 位浮点数。因此,在生产模式下,所有 Java 基本数字类型(除了 long,见下文)都像在 double 上一样实现。主要而言,这意味着整数数据类型(
异常:
try
、catch
、finally
和用户定义的异常照常受支持,尽管Throwable.getStackTrace()
在生产模式下不受支持。
注意:在生产模式下,Java 虚拟机隐式产生的几个基本异常(最显著的是
NullPointerException
、StackOverflowError
和OutOfMemoryError
)不会像这样出现。相反,对于任何隐式生成的异常都会产生一个JavaScriptException
。这是因为底层 JavaScript 异常的性质不能可靠地映射到适当的 Java 异常类型。
断言:
assert
语句在开发模式下始终处于活动状态,因为这是 GWT 库在调试时提供大量有用错误检查的好方法。默认情况下,GWT 编译器会删除并忽略所有断言,但您可以通过向Compiler
指定-ea
标志来在生产模式下启用它们。多线程和同步:JavaScript 解释器是单线程的,因此虽然 GWT 默默接受
synchronized
关键字,但它没有实际效果。与同步相关的库方法不可用,包括Object.wait()
、Object.notify()
和Object.notifyAll()。
编译器会忽略 synchronized 关键字,但如果调用了Object
的相关同步方法,则会拒绝编译代码。反射:为了最大限度地提高效率,GWT 将 Java 源代码编译成一个单片脚本,并且不支持后续的类动态加载。这种和其他优化排除了对反射的一般支持。但是,可以使用 Object.getClass() 查询对象的类名。getName().
终结:JavaScript 在垃圾回收期间不支持对象终结,因此 GWT 无法在生产模式下遵守 Java 终结器。
严格浮点数:Java 语言规范精确地定义了浮点数支持,包括单精度和双精度数字以及
strictfp
关键字。GWT 不支持strictfp
关键字,并且不能保证在转换后的代码中达到任何特定的浮点精度级别,因此您可能想要避免在客户端代码中进行需要保证浮点精度级别的计算。
运行时库支持
GWT 只支持 Java 2 标准版和企业版库中的一小部分可用类,因为这些库非常庞大,并且依赖于 Web 浏览器中不可用的功能。要找出哪些类和方法受核心 Java 运行时包的支持,请参阅 GWT JRE 模拟参考。
提示:如果您从一开始就确保只在客户端代码中使用可翻译类,您将节省很多挫折。为了帮助您尽早识别问题,您的代码在开发模式下运行时会针对 JRE 模拟库进行检查。因此,大多数使用不受支持库的情况会在您第一次尝试运行应用程序时被捕获。所以,尽早运行,并经常运行_。_
JRE 和模拟类之间的区别
GWT 模拟与标准 Java 运行时在某些特定领域存在差异。
正则表达式:Java 正则表达式的语法类似于(但并不完全相同)JavaScript 正则表达式。例如,replaceAll 和 split 方法使用正则表达式。因此,您可能需要小心,只使用在 JavaScript 中具有相同含义的 Java 正则表达式。
序列化:Java 序列化依赖于在编译后的 JavaScript 中不可用的几种机制,例如动态类加载和反射。因此,GWT 不支持标准 Java 序列化。相反,GWT 具有一个RPC 机制,该机制提供自动对象序列化到服务器和从服务器的序列化,以便调用远程方法。
注意:有关 GWT 可以开箱即用地转换的 JRE 类列表,请参阅 GWT JRE 模拟参考。
提供类似功能的类
在某些类中,类的功能过于昂贵而无法完全模拟,因此提供了另一个包中的类似例程。以下是一些提供本机 JRE 功能子集的常用例程。
- com.google.gwt.i18n.client.DateTimeFormat:支持
java.util.DateTimeFormat
的子集。在日期和数字格式部分中查看示例。 - com.google.gwt.i18n.client.NumberFormat:支持
java.util.NumberFormat
的子集。在日期和数字格式部分中查看示例。 - com.google.gwt.user.client.rpc.IsSerializable:类似于
java.io.Serializable
的 GWT RPC 中使用的标记类。 - com.google.gwt.user.client.Timer:一个简化、浏览器安全的计时器类。该类与
java.util.Timer
的作用相同,但由于单线程环境而进行了简化。