1

GWT 通过 JsInterop 开箱即用地提供集合类,但对于 Integer、Long、Char 等(原始对象包装类)则不然。

这有什么原因吗?

为了通过 JsInterop 使这些 Java 模拟类可用,我需要将它们复制到我自己的源中,将它们放在与 gwt-user 中的相同的包中,然后手动修改它们以使用 JsType(并修复所有方法名称冲突,以及通过 JsInterop 只提供一个构造函数)。

除了这样做之外,还有什么更简单的方法可以实现吗?

4

1 回答 1

4

为了让这些“盒装原语”在代码的 Java 端尽可能正确地运行,它们实际上需要是对象,而不是任何可能有意义的原语。

Double 和 Boolean 得到特殊处理(从 GWT 2.6 左右开始),以便它们可以在 Java 和 JS 之间无缝传递。这对这些类型是有意义的,因为它们实际上在可能被分配的值方面是“相同的”(一个 jsboolean总是可以为空的,所以java.lang.Boolean是有道理的,并且一个 jsnumber被指定为一个可以为空的 64- bit IEEE 754 浮点数,所以同样是有意义的java.lang.Double),但这是有代价的:任何 jsnumber总是会通过instanceof Double检查,即使它以 java 开始int

相比之下,其他 Java 原语没有 JS 对应物,因此甚至可能表现得像原语一样奇怪,更不用说对象了。

  • char, byte- 在包含单个字符的“字符串”之外,JS 没有单个字符或字节的概念。只要您处理任何精度问题,您就可以在技术上使用这些原语,但是放弃使用它们的盒装变体的能力并没有真正意义,因为它们并不真正适合。
  • int, short, float- 这些看起来像是作为“数字”从 Java 传递到 JS 是有意义的,但是如果它们作为“数字”返回到 Java,number则它们可能会太大或太精确——如果没有明确的演员表,你就是只是相信它们是有道理的。添加两个floats 也可能会给您带来意想不到的结果,因为 GWT 不模拟 32 位浮点值,只是让 JS 将它们视为 64 位值。与 char/byte 类似,将它们视为对象是没有意义的,因为它们实际上根本不一样。
  • long/java.lang.Long是一个更特殊的情况 - 在 JS 中(直到bigint到达,这仍然​​不是一回事)不可能表示大于 +/- 2^53 的精确整数,因为 JS 中的所有数字都是 64 位浮点数。正确处理 javalong值需要仿真和昂贵的数学运算,因此即使long是来回传递给 JS 的原始 s 也可能会失去精度,或者最终成为 JS 中的 Object(具有“high”、“medium”和“低”位的完整值)。

考虑一些示例代码,您可以在其中装箱一些简单的原语,并与外部 JS 交互:

@JsMethod
public void takeNumber(Number foo) {
  if (foo instanceof Integer) {
    //...
  } else if (foo instanceof Double) {
    //...
  }
}

如果 Integer、Double 等都是 JS 编号的等价物,那么 instanceof 怎么能工作?如果这个方法在 JS 中根本不存在怎么办……你能保证它永远不会被任何JS 方法调用吗?如果参数是 aObject而不是,这样可以传入任意 JS 值,并且您可以测试它是否是 String、Double、Integer 等并做出相应的响应?

如果 Integer 和 Double 在传入和传出 JS 的值为零时都相同怎么办?纯 Java 零在程序的仅 Java 部分中会以不同的方式实现吗?instanceof 在某些部分的行为是否会与其他部分不同,这取决于 JS 值是否有可能到达它们?

--

为了与“外部 JS 世界”的行为方式最一致,在处理这些类型的值时,您几乎总是希望传递 Double、Boolean - 这可以让您测试 null(JS 没有检查器来确认 API 是' 不让你感到惊讶并在它不合法时传递 null ),并进行可能需要的任何类型的边界检查,以查看你应该如何处理该值。对于某些 API,您可以放心地相信它永远不会为空,同样,您通常可以放心地相信它是一个int(例如 JsArray.length),但这些通常是例外情况。为了让您自己的 Java 能够了解这些类型之间的区别,GWT 必须让它们实际上像真正的 Java 类一样运行,并且拥有自己的类型的概念。

--

在这里从主要答案中分心,但是 String 是如何工作的?GWT 能够对 String 进行特殊处理,但最终也必须对 CharSequence、Comparable、Serializble 进行特殊处理,因为您可以从 JS 传入一个 String,将其分配给 type 的字段CharSequence,然后进行instanceof检查Comparable. 出于这个原因,这些类型中的每一个都有一个特殊情况——如果实例实际实现了接口,instanceof则将通过,或者如果实例是纯 JS 字符串,它也会通过。在 Object.equals、hashCode、getClass() 中也需要特殊的大小写以支持 String,以便两个Object恰好都是String的字段知道如何检查它们的类型。现在回到手头的问题,如果((Object) zeroFromJS) instanceof Integer((Object) zeroFromJS) instanceof Double都是真的吗?会((Object) zeroFromJS).getClass()返回什么?

于 2020-06-30T04:15:10.390 回答