Как бороться с наиболее распространенными классами, отсутствующими на 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.