Как бороться с наиболее распространенными классами, отсутствующими в J2ME
-
21-08-2019 - |
Вопрос
Я пытаюсь написать приложение, которое работает на разных Java-платформах, таких как J2SE, J2ME, Android и т. д.Я уже знаю, что мне придется переписать большую часть пользовательского интерфейса для каждой платформы, но хочу повторно использовать основную логику.
Сохранение этого ядра портативным связано с тремя известными мне недостатками:
- Придерживаясь старого Синтаксис Java 1.4, не используя ни одной из приятных особенностей языка Java 5.0.
- только используя внешние библиотеки которые, как известно, работают на этих платформах (то есть:не используйте JNI и не имейте зависимостей от других библиотек, нарушающих эти правила)
- только используя классы, которые присутствуют на всех этих платформах
Я знаю способы преодоления (1):код в стиле 5.0 и автоматически конвертировать его в 1.4 (ретроткач - еще не пробовал, но вроде нормально).
Я думаю (2) это проблема, которую я просто должен принять.
Теперь я хотел бы знать, какой лучший обходной путь для (3), особенно занятия по коллекционированию, по которым я скучаю больше всего.Я могу думать о них:
- Большинство программистов, которых я знаю, просто не используют
Set
,Map
,List
, и т. д.и возврат кVector
и простые массивы.Я думаю, что это в первую очередь делает код уродливым.Но я также знаю, что правильный выбор междуTreeSet/Hashset
илиLinkedList/ArrayList
имеет решающее значение для производительности, и всегда используйтеVector
и массивы не могут быть правильными. - Я мог бы написать свои собственные реализации этих классов.Кажется, это изобретение велосипеда, и я думаю, что не смогу сделать это так хорошо, как другие.
- Поскольку Java имеет открытый исходный код, я мог бы получить исходный код платформы J2SE Collections и включить его в свое приложение при сборке для J2ME.Хотя я не знаю, хорошая ли это идея.Возможно, есть веские причины не делать этого.
- Возможно, уже существуют библиотеки, которые перестраивают наиболее важные функции структуры коллекций, но оптимизированы для систем начального уровня, возможно, за счет отсутствия реализации функций, которые используются нечасто.Знаешь ли ты какой-нибудь?
Спасибо за ваши ответы и мнения!
Редактировать: Наконец я нашел (сложное, но красивое) решение и подумал, что, предоставив свой собственный ответ и приняв его, решение станет видимым вверху.Но, наоборот, мой ответ все еще находится в самом низу.
Решение 2
Прошло много времени с тех пор, как я задавал этот вопрос, и с тех пор, как я нашел хорошее, работающее решение проблемы, но я забыл вам сказать.
Мое основное внимание уделялось Java Collections Framework, которая является частью java.util
упаковка.
Наконец я взял исходный код Suns Java 6.0 и скопировал все классы, принадлежащие платформе Collections, в свой собственный проект.Это был проект Java 6.0, но в качестве пути к классам я использовал jar-файлы из J2ME.Большинство тех классов, которые я скопировал, зависят от других классов J2SE, поэтому зависимости есть неработающие.В любом случае, было довольно легко избавиться от этих зависимостей, оставив все, что связано с сериализацией (что для меня не является приоритетом), и внести некоторые незначительные изменения.
Я скомпилировал все это с помощью компилятора Java 6, а ретротранслятор использовался для портирования полученного байт-кода обратно в Java 1.2.
Следующая проблема — имя пакета, потому что вы не можете доставлять классы из java.util
с приложением J2ME и загрузите их - загрузчик классов начальной загрузки не будет просматривать файл jar приложения, другим загрузчикам не разрешено загружать что-либо с этим именем пакета, а в J2ME вы не можете определять собственные загрузчики классов.Retrotranslator не только преобразует байт-код, но и помогает изменять ссылки на имена в существующем байт-коде.Мне пришлось переместить и переименовать все классы в моем проекте, например. java.util.TreeMap
стал my.company.backport.java.util.TreeMap_
.
Затем я смог написать настоящее приложение J2ME во втором проекте Java 6.0, который ссылался на обычный java.util.TreeMap
, используя общий синтаксис для создания типобезопасных коллекций, скомпилируйте это приложение в байт-код Java 6.0 и запустите его через ретротранслятор, чтобы создать код Java 1.2, который теперь ссылается на my.company.backport.java.util.TreeMap_
.Обратите внимание, что TreeMap
это всего лишь пример, на самом деле он работает для всей структуры коллекций и даже для сторонних J2SE Jars, которые ссылаются на эту структуру.
Полученное приложение можно упаковать в виде файла jar и jad, и оно отлично работает как на эмуляторах J2ME, так и на реальных устройствах (проверено на Sony Ericsson W880i).
Весь процесс кажется довольно сложным, но поскольку я использовал Ant для автоматизации сборки и мне все равно нужен был ретранслятор, то на настройку резервного порта платформы сбора данных потребовались только единоразовые затраты.
Как указано выше, я сделал это почти год назад и пишу это в основном из головы, поэтому надеюсь, что в нем нет ошибок.Если вас интересует более подробная информация, оставьте мне комментарий.У меня есть несколько страниц немецкой документации по этому процессу, которую я мог бы предоставить, если возникнет необходимость.
Другие советы
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.Это неприятно, но если вы хотите, чтобы приложение работало во всех трех этих средах, оно поможет вам в этом.Удачи.
Именно с такой ситуацией мы столкнулись при разработке zxing.Если J2ME находится в вашем списке целей, это, безусловно, ваш ограничивающий фактор.Мы ориентировались на MIDP 2.0/CLDC 1.1.Если у вас аналогичные требования, вам нужно придерживаться Java 1.2.Функции языка Java 1.4 определенно отсутствуют (например, Assert), и в целом вы не найдете ничего после версии 1.2 в J2ME.
Мы не использовали внешние библиотеки, но вы можете без особых проблем упаковать их в развернутый файл .jar.Это приведет к увеличению размера полученного .jar, и это может стать проблемой.(Затем вы можете попробовать оптимизаторы/сжиматели, такие как ProGuard, чтобы смягчить это.)
В итоге я переопределил что-то вроде Collections.sort() и Comparator, поскольку они нам нужны, а в J2ME их нет.Так что да, вы можете рассмотреть возможность сделать это в некоторых случаях, но только там, где это необходимо.
Мы использовали Vector, Hashtable и массивы, поскольку в J2ME другого выбора фактически нет.Я бы просто использовал их, если у вас нет причин не делать этого, и я думаю, это будет производительность.Теоретически производители JVM уже оптимизируют свою реализацию, но это не значит, что вы не можете сделать лучшую...Думаю, я был бы удивлён, если бы оно того стоило в подавляющем большинстве случаев.Просто убедитесь, что вам действительно нужно это сделать, прежде чем прикладывать усилия.
Чтобы ответить на часть вашего вопроса, другая библиотека коллекций будет Яволюция который можно построить для j2me.