Другие возможности Java

JAVA*
Я продолжаю переводить источник первой статьи. Всё больше очевидных вещей, не смотря на это я все же решил, что повторение — не такое плохое занятие.

И коли источник исчерпыет себя — призыв к хабра-java-сообществу: «Don’t be jealous!», дополните этот список в комментариях, поделитесь опытом. А пока — продолжение предыдущей статьи, после монтажа, дубляжа и разбавления собственным опытом:

JDK tools


Почти все в курсе, что в поставку JDK входит внушительное число tools’ов. Однако в повседневной работе, думаю, многие кроме как java, javac, jar не используют. Что же ещё можно взять из папки bin:

  • jstack — позволяет сделать thread dump для любого приложения java по его PID.
  • jvisualvm — новая (1.6_07+) графическая оболочка для мониторинга, профайлинга.
  • javap — декомпилятор дизассемблер, в том числе может показать jvm инструкции.
  • Остальное: java.sun.com/javase/6/docs/technotes/tools/

Java VM


JVM может запускать код, скомпилированный в байт-код из других языков програмирования, таких как Jython, JRuby, Groovy, Scala

System Tray


Начиная с Java 1.6 вы можете добавить иконку в system tray: http://java.sun.com/docs/books/tutorial/uiswing/misc/systemtray.html

Dynamic proxies


Dynamic proxies добавленные в 1.3 позволяют определить во время исполнения (runtime) новый тип по заданному интерфейсу.

Знаете ли Вы, что:



  —  Быстрое копирование массивов возможно через нативный метод System.arraycopy(...)

  —  Ключевое слово this позволяет получить доступ к полям и методам из внутненнего (inner) класса. Например, в случае когда внутренний класс имеет метод или поле с тем же именем: OuterClass.this.methodName() или OuterClass.this.fieldName.
* Только в случае не-статического inner класса — gribozavr

  —  Java 1.5 получила списки аргументов переменной длины:
public void foo(String... bars) {
  for (String bar: bars)
   System.out.println(bar);
}


  —  проверка на null перед instanceof необъязательна:
if (null != aObject && aObject instanceof String) {
тоже самое что и
if (aObject instanceof String)

  —  Существует магическая сериализация Serializable, но не Externalizable объекта через private методы writeObject, readObject
java.sun.com/developer/technicalArticles/Programming/serialization/

  —  Классы для примитивов можно получить, используя int.class, float.class…

  —  Класс String — единственный тип, помимо примитивов, для которого работают + и +=. При этом конструкция str = str + «1» заменяется компилятором на str = new StringBuffer(str).append(«1»).toString(). Вы все ещё конкатенируете строки в цикле?
* Начиная с Java 1.5 используется StringBuilder — malkolm

  —  C-style sprintf возможен в java, попробуйте String.format().
String w = «world»;
String s = String.format(«Hello %s %d», w, 3);


  —  Для float i = Float.NaN – выражение i == i равно false
* Это требование IEEE 754. Проверить double на NaN можно при помощи Double.isNan() — gribozavr

Полузакрытые конструкторы



Источник: javaekspert.blogspot.com/2007/11/semi-private-constructors.html

Очень часто возникает необходимость сделать создание объекта недоступным для других классов (например, при использовании фабрик) или закрыть доступ к части конструкторов, объявив их «частной собственностью» объекта. Однако приходится наступать на собственные же грабли во время модульного тестирования – невозможно создать объект.

На помощь приходят полузакрытые конструкторы, использование protected конструкторов и анонимных классов. Пример:
Если класс User хочет скрыть один из своих конструкторов User(int id), оставив доступным только User(String name) – это его право. Однако, объявив класс следующим образом (именно protected, а не private):

public class User { // важно что User не final
  protected User(int id) {…}
  public User(String name) {
    this(getId(name));
  }
}


мы оставляем лазейку для последующего использования первого конструктора, а именно:

public class TestUser {  
  public void testUserIdConstructor() {    
    User hack = new User(1) {};  
  }
}


И переменной hack присвоили объект анонимного класса, унаследованного от User, в добавок, вызвав конструктор User(1).

Self-bound generics



class SelfBounded<T extends SelfBounded> {
}

Из статии Брюса Эккеля www.artima.com/weblogs/viewpost.jsp?thread=136394
В нагрузку ОГРОМНЫЙ FAQ по generics – всё что вы боялись спросить: www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html

И снова про enum



Enum могут реализовать интерфейс

public interface Room {
  public Room north();
  public Room south();
  public Room east();
  public Room west();
}

public enum Rooms implements Room {
  FIRST {
    public Room north() {
      return SECOND;
    }
  },
  SECOND {
    public Room south() {
      return FIRST;
    }
  }

  public Room north() { return null; }
  public Room south() { return null; }
  public Room east() { return null; }
  public Room west() { return null; }
}


Черная магия


По другому это назвать язык не поворачивается. Барабанная дробь…
Класс sun.misc.Unsafe позволяет реализовать прямое управление памятью в вашем приложении. Вы сможете:
  1. Создать объект без вызова конструктора
  2. Выбросить Exception без определения этого Exception в списке throws.
  3. Выделять, освобождать, копировать блоки памяти
  4. Брать и возвращать монитор объекта (lock/unlock) без объявления synchronized
  5. Объявить класс из байт-кода — этот пункт огорчает людей, работавших с кастомным ClassLoader'ом

Зачем это всё, хочется мне спросить? Не нахожу ответа, и, думаю, баловство с этим классом может убить JVM

Источник —
http://www.docjar.com/html/api/ClassLib/Common/sun/misc/Unsafe.java.html
и ещё одна занимательная ссылка, уже на русском —
http://wasm.ru/article.php?article=unsjav1
http://wasm.ru/article.php?article=unsafe_ii
использование в open source:
google code search

* Source code was highlighted with Source Code Highlighter.
+42
23 августа 2009, 21:49
49
sedovmik 64,3

комментарии (25)

+3
sse #
По поводу черной магии и пункта 5 — это же самое можно делать кастомным класслоадером, так что было бы интересно узнать про применение именно Unsafe.

И, простите, безотносительно
>>без вывоза конструктора
улыбнуло :)
0
sedovmik #
спасибо, исправил. А по поводу Unsafe — класс не документирован. Можно попробовать скачать исходники, однако java.net уже как два дня на maintenance. Ну или почитать Unsafe java на wasm.ru: часть 1 и часть 2

+1
TheShade #
> узнать про применение Unsafe
Google Code Search вам в помощь.
+1
gribozavr #
> Ключевое слово this позволяет получить доступ к полям и методам из внутненнего (inner) класса.

Только в случае не-статического inner класса.

> Для float i = Float.NaN – выражение i == i равно false

Сказали бы почему это так и что с этим делать. Это требование IEEE 754. Проверить double на NaN можно при помощи Double.isNan().
0
sedovmik #
Спасибо. С Вашего разрешения добавлю в текст статьи
+3
Scala #
javap всё же дизассемблер, а не декомпилятор.
+1
garbuz #
Я думаю, что вряд ли буду использовать бОльшую часть описанного, но вот про конкатенацию строк действительно полезно :)
+2
TheShade #
sun.misc.Unsafe потому и не является частью публичного API, чтобы им не пользовались лишний раз. А нужен он для реализации некоторых вещей внутри стандартной библиотеки без походов в native или для быстрого доступа к функциональности виртуальной машины. Можно просто взять и посмотреть живые примеры его использования.
0
maslyak #
я так понимаю с помощью sun.misc.Unsafe прикручивают к джаве указатели? :)
0
EaE #
sun.misc.Unsafe это частный класс частной проприетарной либы одной частной конторки. Ни к JLS, ни к JVMS пакеты sun.* и com.sun.* отношения не имеют и уж тем более их тупо ет ни в одной другой реализации JVM (коих довольно-таки и у каждой свой смысл).
0
EaE #
*нет
0
mrskam #
А что же они тогда делают в rt.jar в JRE от Sun?
0
EaE #
детали имплементации
+1
mrskam #
Ясно, спасибо.
+2
TheShade #
Кстати зря вы, у многих реализаций JVM есть собственные варианты sun.misc.Unsafe, посмотрите сюда. Этот инструмент достаточно распространён и используется в системном Java-коде довольно часто, поэтому приходится его неофициально поддерживать.
0
EaE #
Ключевые слова — «в системном коде». Черт, да с тем же успехом там может быть код, выделяющий память и возвращающий указатели на нее, да хоть полная реализация сишной модели работы с памятью; все равно это будут детали имплементации одной конкретной JVM (и то, что большинство JVM в той или иной степени стырены с сановской реализации, не умаляет этого факта).

Иными словами: используя эти классы и рассчитывая на их наличие в составе JVM вы пишете не на Java под ява-машину, а на каком-то своем выдуманном, очень похожем на яву языке, под совершенно левый интерпретатор этого языка, и никакой гарантии, что ваш код запустится у пользователя, у вас нет (если вы только не поставляете JVM в комплекте со своим коммерческим продуктом; и, конечно, уже договорились с Sun на эту тему). На какой-нибудь WebSphere, которая запускается на IBM-овской JVM, ваше решение просто не взлетит, да и (забавно кстати, в ru_java мы сейчас это же самое обсуждаем) сама необходимость применить подобные решения — с хорошей вероятностью показатель ошибки в архитектуре приложения.
0
TheShade #
Про совместимость — это понятно. Я спорю с утверждением, что такие внутренние классы являются принадлежностью исключительно Sun JRE, а другими реализациями по соображениям расовой чистоты не поддерживаются. Это совсем не так. Многие реализации вынуждены идти на поводу и поддерживать такие нестандартные расширения, чтобы быть совместимыми с reference implementation. Примеры я вам привёл в прошлом комменте: это и GNU Classpath, и Android, и Apache Harmony, и CacaoVM и чёрта в ступе ещё. Вся суета вокруг Unsafe как раз затем, чтобы разработав системный модуль, работающий под Harmony, можно было его без особенного геморроя запустить его на других JVM, в т.ч. на Sun.

Про использование Unsafe в пользовательском коде я согласен — это практически чистый no-go. А в системном никуда не денешься, если только не смотреть по сторонам в сторону MMTk-евского org.vmmagic.*

0
EaE #
А, понял.
А можно примеры «системного кода», кстати?
0
TheShade #
Посмотрите же в CodeSearch наконец: типичные случаи java.util.concurrent.atomic, java.lang.reflect, встречаются ещё части java.io, касающиеся сериализации, плюс полу-нативные AWT-стабы.
0
EaE #
Окей, теперь я вконец запутан. Все вышеперечисленное — опять детали реализации JVM, которые пользователю (т.е. не человеку, разрабатывающему собственную JVM) не видны. Ладно, это понятно. Зато теперь я опять не понимаю, кто у кого «вынужден идти на поводу». Тот факт, что это удобный инструмент для реализации механизмов JVM — это понятно, но это факт отнюдь не из Java, скорее уж, из жизни сишников. То, что многие компании, пишушие собственные JVMы, решают не изобретать велосипедов, а переиспользуют имеющиеся Unsafe биндинги в натив — это тоже понятно; но ведь ни Sun после этого не вынужден поддерживать для них актуальную версию Unsafe, ни для них это не является вынужденным решением, а всего лишь способом срезать путь (и код они в дальнейшем поддерживают уже самостоятельно, ну либо перетыривают более свежие версии), ни уж тем более конечный пользователь ничего об этом не знает. Т.е. опять же, это не ява, так же, как не ява тот компилятор, что используется, чтобы собрать бинарники JVM.
+1
TheShade #
Да, под системным кодом я имел в виду реализацию близко-VM-ных классов, самой VM/GC/JIT и стандартной библиотеки. К пользовательскому коду это отношения почти никогда не имеет, пользователь на эти внутренние классы надеяться не вправе, потому их пользователю в документации не показывают.

«Срезание пути» часто является вынужденным решением, альтернативой которому была бы поддержка собственных версий некоторых модулей. Например, куда проще поддержать Unsafe и получить нахаляву java.util.concurrent, чем держать собственную версию j.u.c, заточенную под собственную реализацию JRE. Когда речь идёт о сотнях тысяч строк кода, есть над чем задуматься.

И хотя de jure это не является частью стандарта, de facto соглашения на контракты к Unsafe есть. В конечном итоге, это поведение reference implementation.
0
EaE #
агам.
+1
nva #
Про серриализацию, есть более интересная статья на русском www.skipy.ru/technics/serialization.html
Там кстати много статей по базовым вещам с неплохой детализацией.
+1
malkolm #
Клева было бы назвать фишку со списком аргументов произвольной длинны вслух по имени: Varargs.

С пятой версии Java конкатенация строк компилятором приводится к цепочке на базе StringBuilder, а не StringBuffer. Исправьте или сделайте объяснение.

Ну и да, ваша магия под номером 5 — это просто ха. Я тогда целыми днями занимаюсь черной магией.
0
romik #
С применениме «Полузакрытых конструкторов», как вы их называете, следует быть осторожным.
Часто метод equals пишется так, что
new User(1) {} != new User(1),
поскольку это разные классы. Соответственно, в тестах можно нарваться на поведение, отличное от обычного.

В общем, я за другие способы, хотя и про этот знать тоже неплохо.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.