Как бороться с наиболее распространенными классами, отсутствующими на J2ME

Я пытаюсь закодировать приложение, которое запускает разные платформы Java, такие как J2SE, J2ME, Android и т.д. Я уже знаю, что мне придется переписать большую часть пользовательского интерфейса для каждой платформы, но хочу повторно использовать ядро логика.

Сохранение этой основной переносимости связано с тремя недостатками, о которых я знаю:

  • Сохранение старого синтаксиса Java 1.4, не использующего каких-либо хороших языковых возможностей Java 5.0
  • только используя внешние библиотеки, которые, как известно, работают на этих платформах (то есть: не используйте JNI и не имеют зависимостей от других libs, которые нарушают эти правила).
  • только используя классы, которые присутствуют на всех этих платформах

Я знаю, как преодолеть (1): код в стиле 5.0 и автоматически преобразовать его в 1.4 (retroweaver - еще не пробовал, но, похоже, хорошо).

Я думаю, что (2) - это проблема, которую я просто должен принять.

Теперь я хотел бы узнать, какой лучший рабочий стол для (3), особенно для классов коллекций, которые я больше всего не хватает. Я могу думать о них:

  • Большинство программистов, которых я знаю, просто не используют Set, Map, List и т.д. и возвращаются к Vector и простым массивам. Я думаю, что это делает код уродливым в первую очередь. Но я также знаю, что правильный выбор между TreeSet/Hashset или LinkedList/ArrayList имеет решающее значение для производительности, и всегда использовать Vector, а массивы не могут быть прав.
  • Я мог бы кодировать свои собственные реализации этих классов. Кажется, это изобретает колесо, и я думаю, что я не смог бы сделать это так хорошо, как это сделали другие.
  • Так как Java является открытым исходным кодом, я могу захватить исходный код структуры коллекций J2SE и включить в мое приложение при создании для J2ME. Однако я не знаю, хорошая ли это идея. Возможно, есть веские причины не делать этого.
  • Возможно, там уже есть библиотеки, которые перестраивают наиболее важные функции рамки коллекций, но оптимизированы для низкопроизводительных систем, возможно, не реализуя функциональность, которая используется нечасто. Знаете ли вы кого-нибудь?

Спасибо за ваши ответы и мнения!

Изменить: Наконец-то я нашел (сложное, но приятное) решение, и, подумал я, предоставив свой собственный ответ и приняв его, решение станет видимым наверху. Но, наоборот, мой ответ все еще находится на самом дне.

Ответы

Ответ 1

Прошло некоторое время с тех пор, как я задал этот вопрос, и я с тех пор, как нашел хорошее, работающее решение проблемы, но с тех пор я забыл сказать вам.

Основное внимание было уделено структуре коллекций Java, которая является частью пакета java.util.

Наконец, я взял исходный код Suns Java 6.0 и скопировал все классы, принадлежащие структуре Collections, в собственный проект. Это был проект Java 6.0, но я использовал jars из J2ME как classpath. Большинство из этих классов, которые я скопировал, зависит от других классов J2SE, поэтому существуют разломанные зависимости. Во всяком случае, было довольно легко сократить эти зависимости, исключив все, что связано с сериализацией (что для меня не является приоритетом) и некоторыми незначительными корректировками.

Я скомпилировал все это с помощью компилятора Java 6, а ретротранслятор был использован для переноса полученного байт-кода обратно в Java 1.2.

Следующая проблема - это имя пакета, потому что вы не можете доставлять классы из java.util с помощью приложения J2ME и загружать их - загрузчик класса bootstrap не будет искать в файле jar приложений, другие загрузчики не разрешены загрузить что-то с этим именем пакета, а на J2ME вы не можете определить пользовательские загрузчики классов. Retrotranslator не только преобразует байт-код, но также помогает изменять ссылки на имена в существующем байт-коде. Мне пришлось переместить и переименовать все классы в моем проекте, например. java.util.TreeMap стал my.company.backport.java.util.TreeMap_.

Я смог написать фактическое приложение J2ME во втором проекте Java 6.0, который ссылался на обычный java.util.TreeMap, используя общий синтаксис для создания коллекций, защищенных типами, скомпилировал это приложение для байтового кода Java 6.0 и запускал его через backtranslator для создания кода Java 1.2, который теперь ссылается на my.company.backport.java.util.TreeMap_. Обратите внимание, что TreeMap является просто примером, он действительно работает для всей структуры коллекций и даже для сторонних J2SE-баров, которые ссылаются на эту структуру.

Полученное приложение может быть упаковано в виде jar и jad файла и отлично работает как на эмуляторах J2ME, так и на реальных устройствах (протестировано на Sony Ericsson W880i).

Весь процесс кажется довольно сложным, но поскольку я использовал Ant для автоматизации сборки, и мне все-таки нужен ретранслятор, для установки фреймворка структуры коллекции было однократное накладное время.

Как уже говорилось выше, я сделал это почти год назад, и писал это в основном из верхней части головы, поэтому надеюсь, что ошибок нет. Если вас интересует более подробная информация, оставьте мне комментарий. У меня есть несколько страниц немецкой документации об этом процессе, которые я мог бы предоставить, если есть спрос.

Ответ 2

J2ME является жестоким, и вам просто нужно смириться с тем, чтобы делать это без каких-либо тонкостей других платформ. Привыкайте к Hashtable и Vector и пишите свои собственные обертки поверх них. Кроме того, не делайте ошибки, полагая, что J2ME является стандартным, так как каждый производитель JVM может делать что-то совершенно по-разному. Вначале я бы не стал беспокоиться о производительности, так как получить правильность J2ME достаточно сложно. Можно написать приложение, которое работает через J2ME, J2SE и Android, как я это делал, но он требует много работы. Одно из предположений, что у меня будет, это то, что вы пишете ядро ​​логики приложения и строго храните его в java.lang, java.util и java.io. В любом месте, где вы собираетесь делать что-то, что может взаимодействовать с платформой, например файловой системой или сетью, вы можете создать интерфейс, с которым взаимодействует ваш код основного приложения, что у вас разные реализации для разных сред. Например, вы можете иметь интерфейс, который обертывает материал HTTP, и использует javax.microedition.io.HttpConnection с J2ME и java.net.HttpURLConnection на Android. Это боль, но если вы хотите поддерживать приложение, работающее во всех трех этих средах, оно может получить вас там. Удачи.

Ответ 3

Мы столкнулись именно с этой ситуацией при разработке zxing. Если J2ME находится в списке целей, это ваш ограничивающий фактор. Мы ориентировались на MIDP 2.0/CLDC 1.1. Если у вас есть аналогичное требование, вам нужно придерживаться Java 1.2. Возможности языка Java 1.4 определенно отсутствуют (например, утверждают), и в целом вы не найдете ничего после 1.2 в J2ME.

Мы не использовали внешние библиотеки, но вы можете скомпилировать их в свой развернутый файл .jar с небольшими проблемами. Это приведет к увеличению размера .jar, и это может быть проблемой. (Тогда вы можете попробовать оптимизаторы/сжимающие устройства, такие как ProGuard, чтобы смягчить это.)

В итоге я переопределял что-то вроде Collections.sort() и Comparator, так как мы нуждались в них, и они не в J2ME. Так что вы можете подумать об этом в случаях, хотя только там, где это необходимо.

Мы использовали Vector и Hashtable и массивы, поскольку в J2ME нет другого выбора. Я бы просто использовал их, если у вас нет причин, и это будет производительность, я думаю. Теоретически производители JVM уже оптимизируют свою реализацию, но это не значит, что вы не смогли бы сделать лучшую... Наверное, я был бы удивлен, если бы это было в огромном большинстве случаев. Просто убедитесь, что вам действительно нужно это сделать, прежде чем прикладывать усилия.

Ответ 4

Чтобы ответить на часть вашего вопроса, другая библиотека коллекций будет Javolution, которая может быть построена для j2me.