13

我正在尝试编写一个运行不同 Java 平台(如 J2SE、J2ME、Android 等)的应用程序。我已经知道我必须为每个平台重写大部分 UI,但希望重用核心逻辑。

保持这个核心的可移植性涉及我知道的三个缺点:

  1. 保持旧的Java 1.4 语法,不使用 Java 5.0 的任何优秀语言特性
  2. 仅使用已知可在这些平台上工作的外部库(即:不要使用 JNI 并且不依赖于违反此规则的其他库)
  3. 仅使用所有这些平台上存在的类

我知道克服(1)的方法:以 5.0 样式编写代码并自动将其转换为 1.4(retroweaver - 尚未尝试过,但似乎还可以)。

我认为(2)是一个我必须接受的问题。

现在我想知道(3)的最佳工作方法是什么,尤其是我最想念的集合类。我能想到那些:

  • 我认识的大多数程序员只是不使用Set, Map,List等,而是回退到Vector普通数组。我认为这首先使代码变得丑陋。但我也知道TreeSet/Hashsetor之间的正确选择LinkedList/ArrayList对性能至关重要,并且总是使用Vectorand 数组是不对的。
  • 我可以编写我自己的这些类的实现。这似乎是在重新发明轮子,我认为我不能像其他人那样做得好。
  • 由于 Java 是开源的,因此在为 J2ME 构建时,我可以获取 J2SE Collections 框架的源代码并将其包含到我的应用程序中。不过,我不知道这是否是个好主意。也许有充分的理由不这样做。
  • 也许已经有一些库,它们重建了集合框架最重要的特性,但针对低端系统进行了优化,也许是通过不实现不经常使用的功能。你知道任何?

感谢您的回答和意见!

编辑:我终于找到了一个(复杂但很好的)解决方案,我想通过提供我自己的答案并接受它,该解决方案将在顶部可见。但相反,我的答案仍然处于最底层。

4

4 回答 4

13

J2ME 是残酷的,你将不得不放弃自己去做没有其他平台的一些细节。习惯 Hashtable 和 Vector,并在它们之上编写自己的包装器。此外,也不要错误地认为 J2ME 是标准的,因为每个制造商的 JVM 可以以截然不同的方式做事。最初我不会太担心性能,因为仅仅在 J2ME 上获得正确性就足够了。可以编写一个跨 J2ME、J2SE 和 Android 运行的应用程序,正如我所做的那样,但这需要大量工作。我的一个建议是,您编写应用程序逻辑的核心并严格遵守 java.lang、java.util 和 java.io。任何你将要做可能与平台交互的事情的地方,例如文件系统或网络,您可以创建一个与您的核心应用程序代码交互的接口,您可以为不同的环境提供不同的实现。例如,您可以拥有一个封装 HTTP 内容的接口,并在 J2ME 和 Android 上使用 javax.microedition.io.HttpConnection 和 java.net.HttpURLConnection。这很痛苦,但如果你想维护一个在所有这三个环境中运行的应用程序,它可以让你到达那里。祝你好运。但是,如果您想维护在所有这三个环境中运行的应用程序,它可以帮助您实现目标。祝你好运。但是,如果您想维护在所有这三个环境中运行的应用程序,它可以帮助您实现目标。祝你好运。

于 2009-05-15T16:34:23.040 回答
12

自从我问这个问题以来已经有一段时间了,自从我找到了一个很好的、有效的解决方案以来,我已经忘记了告诉你。

我的主要关注点是 Java 集合框架,它是java.util包的一部分。

我终于拿到了 Suns Java 6.0 的源代码,并将属于 Collections 框架的所有类复制到我自己的项目中。这是一个 Java 6.0 项目,但我使用 J2ME 中的 jar 作为类路径。我复制的大多数类都依赖于其他 J2SE 类,因此存在损坏的依赖关系。无论如何,通过省略所有处理序列化(这对我来说不是优先事项)和一些小的调整来减少这些依赖是很容易的。

我用 Java 6 编译器编译了整个东西,然后使用逆向翻译器将生成的字节码移植回 Java 1.2。

下一个问题是包名,因为您不能java.util使用 J2ME 应用程序传递类并加载它们 - 引导类加载器不会查看应用程序 jar 文件,其他引导加载器不允许使用该包加载某些内容名称,并且在 J2ME 上您不能定义自定义类加载器。Retrotranslator 不仅可以转换字节码,还可以帮助更改现有字节码中的名称引用。我不得不移动并重命名项目中的所有类,例如java.util.TreeMap成为my.company.backport.java.util.TreeMap_.

我能够在第二个 Java 6.0 项目中编写实际的 J2ME 应用程序,该项目引用了通常的java.util.TreeMap.,使用通用语法创建类型安全的集合,将该应用程序编译为 Java 6.0 字节代码,并通过逆向翻译器运行它以创建 Java 1.2 代码现在引用my.company.backport.java.util.TreeMap_. 请注意,这TreeMap只是一个示例,它实际上适用于整个集合框架,甚至适用于引用该框架的 3rd 方 J2SE Jars。

生成的应用程序可以打包为 jar 和 jad 文件,并且可以在 J2ME 模拟器和实际设备上正常运行(在索尼爱立信 W880i 上测试)。

整个过程看起来相当复杂,但由于我使用 Ant 进行构建自动化,而且无论如何我都需要重新翻译器,因此设置集合框架反向移植只需要一次性开销。

如上所述,我在将近一年前就完成了这项工作,并且大部分时间都是从头顶写的,所以我希望其中没有错误。如果您对更多细节感兴趣,请给我留言。我有几页关于该过程的德语文档,如果有任何需求,我可以提供。

于 2010-07-04T18:47:37.107 回答
3

我们在开发zxing时就遇到了这种情况。如果 J2ME 在您的目标列表中,那么到目前为止这是您的限制因素。我们针对 MIDP 2.0 / CLDC 1.1。如果你有类似的需求,你需要坚持 Java 1.2。Java 1.4 语言特性绝对不存在(如断言),并且通常在 J2ME 1.2 之后您将找不到任何东西。

我们没有使用外部库,但是,您可以轻松地将它们打包到部署的 .jar 文件中。它会使生成的 .jar 更大,这可能是一个问题。(然后你可以尝试像 ProGuard 这样的优化器/收缩器来缓解这种情况。)

我最终确实重新实现了诸如 Collections.sort() 和 Comparator 之类的东西,因为我们需要它们并且它们不在 J2ME 中。所以是的,您可能会考虑在某些情况下这样做,尽管仅在必要时。

我们使用了 Vector 和 Hashtable 以及数组,因为在 J2ME 中确实没有其他选择。除非您有理由不使用它们,否则我只会使用它们,我猜这将是性能。理论上,JVM 制造商已经在优化他们的实现,但这并不意味着你不能做出更好的实现......我想如果在绝大多数情况下它是值得的,我会感到惊讶。在付出努力之前,请确保您确实需要这样做。

于 2009-05-15T01:02:05.793 回答
2

要回答您的部分问题,另一个集合库将是Javolution,它可以为 j2me 构建。

于 2009-05-14T11:23:24.873 回答