如何处理J2ME上缺少的最常见的类

时间:2009-05-13 18:01:09

标签: java java-me cross-platform portability midp

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

保持这个核心便携性涉及三个我所知道的缺点:

  1. 保持旧的 Java 1.4语法,不使用Java 5.0的任何优秀语言功能
  2. 仅使用已知在这些平台上工作的外部库(即:不使用JNI并且不依赖于违反此规则的其他库)
  3. 仅在所有这些平台上使用
  4. 我知道如何克服(1):5.0风格的代码并自动将其转换为1.4( retroweaver - 尚未尝试过,但似乎没问题)。

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

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

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

    感谢您的回答和意见!

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

4 个答案:

答案 0 :(得分:13)

J2ME是残酷的,你只需要在不使用其他平台的一些细节的情况下辞职。习惯Hashtable和Vector,并在这些上面编写自己的包装器。此外,不要错误地假设J2ME也是标准的,因为每个制造商的JVM都可以以完全不同的方式做事。我最初并不担心性能,因为只是在J2ME上获得正确性就足够了。可以编写一个运行在J2ME,J2SE和Android上的应用程序,就像我做的那样,但它需要做很多工作。我有一个建议是你编写应用程序逻辑的核心并严格遵守java.lang,java.util和java.io.在您可能正在进行可能与平台交互的任何地方(例如文件系统或网络)的任何地方,您可以创建核心应用程序代码与之交互的接口,以便为不同的环境提供不同的实现。例如,您可以拥有一个包装HTTP内容的接口,并在Android上使用javax.microedition.io.HttpConnection和J2ME以及java.net.HttpURLConnection。这很痛苦,但是如果你想维护一个在所有这三个环境中运行的应用程序,它可以帮助你。祝你好运。

答案 1 :(得分:12)

自从我问这个问题以来已经有一段时间了,而且自从我为这个问题找到了一个很好的,有效的解决方案之后,我一直在努力告诉你。

我主要关注的是Java Collections Framework,它是java.util包的一部分。

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

我使用Java 6编译器编译了整个内容,并使用反向转换器将生成的字节码移植回Java 1.2。

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

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

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

整个过程看起来相当复杂,但由于我使用Ant进行构建自动化,而且我还需要重新编译器,所以只有一次性开销来设置集合框架backport。

如上所述,我差不多一年前完成了这项工作,并且大部分是从头脑中写出来的,所以我希望它没有错误。如果您对更多细节感兴趣,请给我留言。我有几页关于该过程的德文文档,如果有需求,我可以提供。

答案 2 :(得分:3)

我们在开发zxing时遇到了这种情况。如果J2ME在您的目标列表中,那么这是您的限制因素。我们针对MIDP 2.0 / CLDC 1.1。如果您有类似的要求,则需要坚持使用Java 1.2。 Java 1.4语言功能绝对不存在(如assert),一般情况下,在J2ME 1.2之后你找不到任何东西。

我们没有使用外部库,但是,您可以将它们打包到已部署的.jar文件中,而不会遇到任何麻烦。它会使得.jar变得更大,这可能是一个问题。 (然后你可以尝试像ProGuard这样的优化器/ shrinkers来缓解这种情况。)

我最终重新实现了Collections.sort()和Comparator之类的东西,因为我们需要它们而且它们不在J2ME中。所以,你可以考虑在案件中这样做,尽管只是在必要时。

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

答案 3 :(得分:2)

要回答部分问题,可以为j2me构建另一个集合库Javolution