Advanced Topics in Programming Languages: The Java Memory…

Алгоритм сериализации объектов в Java

Сериализацией (Serialization) называют процесс сохранения состояния объекта в последовательность байт, в то время как десериализацией называют обратный процесс, формирующий объект из последовательности байт. Java Serialization API предоставляет разработчикам механизм, позволяющий производить сериализацию/десериализацию объектов. В этой статье вы узнаете, как сериализовать объект, и когда сериализация является необходимой. Вы так же узнаете, как работает алгоритм сериализации в Java на примере, иллюстрирующем формат сериализации объектов на низком уровне.

Итак, зачем нужна сериализация?

На сегодняшний день, традиционное приложение уровня предприятия состоит из разнообразных компонентов и распределено между различными системами и сетями. В Java всё представлено в качестве объектов (за исключением примитивных типов); для того, чтобы два объекта могли взаимодействовать между собой, должен существовать механизм, позволяющий обмениваться данными. Одним из путей достижения такого взаимодействия может служить разработка протокола обмена объектами. В этом случае получатель объекта должен работать по такому же протоколу, по которому работает отправитель объекта, что в свою очередь может привести к затруднениям при интеграции ваших компонентов со сторонними компонентами. Из этого следует, что протокол должен быть простым и обобщённым, что в свою очередь в Java достигается с помощью сериализации. (more…)

В чем различие между использованием оператора instanceof и Class.isAssignableFrom(…) метода?

Этим вопросом я задавался не один раз при разработке кода, определяющего принадлежность определённого экземпляра класса к определённой иерархии наследования, а так же принадлежность к реализации определённого интерфейса. В Java существует несколько подходов к решению данной проблемы, из которых мы обратим внимание на различие между использованием оператора instanceof и Class.isAssignableFrom(Class<?> cls) метода. Одним из главных различий является то, что использование оператора instanceof позволяет выявлять ошибки на уровне компиляции кода. Пример кода, позволяющий выявить ошибку времени компиляции, приведён в Листинге 1.

Листинг 1. Некорректное использование оператора instanceof

if(String.class instanceof Integer) {
    System.out.println("true");
}

В то время как код, приведённый в Листинге 2, в конечном итоге будет выполнен без каких-либо ошибок.

Листинг 2. Использование метода Class.isAssignableFrom(Class<?> cls)

if(Integer.class.isAssignableFrom(String.class)) {
    System.out.println("true");
}

Итак, использование оператора instanceof имеет место тогда, когда Вы четко знаете, в какой иерархии наследования участвует класс и какие интерфейсы он реализует, в противном случае целесообразно посмотреть в сторону Class.isAssignableFrom(Class<?> cls) метода, использование которого в свою очередь позволяет реализовать более гибкий код, предоставляющий возможность композиции.

Java Reflection: работа с приватными полями и методами

Используя механизм рефлексии в Java, клиент получает широкие возможности как для извлечения значений из инкапсулированных полей класса, так и для получения значений, возвращаемых инкапсулированными методами класса.

Работа с приватными полями

Для получения доступа к приватным полям класса, прежде всего необходимо получить экземпляр класса java.lang.reflect.Field. Для этого нужно воспользоваться Class.getDeclaredField(String name) либо Class.getDeclaredFields() методами класса Class. Обратите внимание на то, что методы Сlass.getField(String name) и Class.getFields() предоставляют доступ только к полям, объявленных с  модификатором доступа public. Из этого следует, что они не предоставляют возможности для получения полей, объявленных с модификаторами доступа protected и private.

Рассмотрим более детально доступ к приватным полям класса на примерах, приведённых в Листингах 1 и 2.

Листинг 1. Класс PrivateObject

public class PrivateObject {

  private String privateString = null;

  public PrivateObject(String privateString) {
    this.privateString = privateString;
  }
}

Листинг 2. Реализация доступа к приватному полю класса PrivateObject

PrivateObject privateObject = new PrivateObject("The Private Value");

Field privateStringField = PrivateObject.class.getDeclaredField("privateString");

privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(privateObject);
System.out.println("fieldValue = " + fieldValue);

При выполнении кода, приведённого в Листинге 2, на экран будет выведено сообщение “fieldValue = The Private Value”, содержащее значение приватного поля privateString класса PrivateObject. Обратите внимание на использование метода PrivateObject.class.getDeclaredField(”privateString”). Этот метод возвращает поле именно того класса, у которого непосредственно вызывается метод getDeclaredField(String name). Другими словами, этот метод не предоставляет доступ к полям, объявленных в суперклассах. Далее, вызывая метод setAccessible(true) у экземпляра privateStringField класса Field, вы тем самым предоставляете механизму рефлексии доступ к приватному полю privateString объекта privateStringField.

Работа с приватными методами

Для получения доступа к приватным методам класса, прежде всего необходимо получить экземпляр класса java.lang.reflect.Method. Для этого нужно воспользоваться Class.getDeclaredMethod(String name, Class[] parameterTypes) либо Class.getDeclaredMethods() методами класса Class. Заметьте, что методы Сlass.getMethod(String name) и Class.getMethods() предоставляют доступ только к методам, объявленных с модификатором доступа public. Из этого следует, что они не предоставляют возможности для получения методов, объявленных с модификаторами доступа protected и private.

Рассмотрим более детально доступ к приватным методам класса на примерах, приведённых в Листингах 3 и 4.

Листинг 3. Класс PrivateObject с приватным методом getPrivateString()

public class PrivateObject {

  private String privateString = null;

  public PrivateObject(String privateString) {
    this.privateString = privateString;
  }

  private String getPrivateString(){
    return this.privateString;
  }
}

Листинг 4. Реализация доступа к приватному методу класса PrivateObject

PrivateObject privateObject = new PrivateObject("The Private Value");

Method privateStringMethod = PrivateObject.class.getDeclaredMethod("getPrivateString", null);

privateStringMethod.setAccessible(true);

String returnValue = (String)
        privateStringMethod.invoke(privateObject, null);

System.out.println("returnValue = " + returnValue);

При выполнении кода, приведённого в Листинге 4, на экран будет выведено сообщение “returnValue = The Private Value”. Данное сообщение содержит значение “The Private Value”, возвращаемое методом getPrivateString(). Обратите внимание на использование метода PrivateObject.class.getDeclaredMethod(”getPrivateString”, null). Этот метод возвращает метод именно того класса, у которого непосредственно вызывается метод getDeclaredMethod(String name, Class[] parameterTypes). Другими словами, этот метод не предоставляет доступ к методам, объявленных в суперклассах. Далее, вызывая метод setAccessible(true) у экземпляра privateStringMethod класса Method, вы тем самым предоставляете механизму рефлексии доступ к приватному методу getPrivateString() объекта privateStringField.

Источник: http://tutorials.jenkov.com/

Vector или ArrayList – что лучше и почему?

Найдите разницу между Vector’ом и ArrayList’ом.

Иногда лучше использовать Vector, иногда ArrayList, в некоторых случаях лучше не использовать ни то ни другое.  Существует четыре фактора, влияющих на принятие решения – что и когда лучше использовать, а именно:

  • API
  • Синхронизация
  • Хранение данных
  • Реализация

Давайте более подробно остановимся на каждом из них.

API

В издании The Java Programming Language (Addison-Wesley, June 2000) Кен Арнолд, Джеймс Гослинг и Девид Холмс описывают Vector как аналог ArrayList’а. Из этого следует, что с точки зрения API, оба класса очень похожи. Тем не менее, между этими двумя классами всё-таки есть существенные различия.

Синхронизация

Экземпляры класса Vector являются синхронизированными и каждый метод класса Vector является потокобезопасным, в то время как ArrayList имеет прямо противоположное описание: он не является синхронизированным и не является потокобезопасным. Из этого следует, что использование Vector’a в конечном итоге понижает производительность из-за обеспечения синхронизированного доступа к данным коллекции. Поэтому, если вам не нужна коллекция, обеспечивающая потокобезопасный доступ к данным (т.е. Vector), используйте ArrayList, зачем платить больше?

Хранение данных

Обе коллекции Vector и ArrayList используют массив для хранения данных. Вам нужно помнить об этом всегда. Массив, хранящий элементы, расширяется в том случае, когда он уже является полностью заполненным в момент добавления нового элемента. Каким образом реализуется расширение массива? Если мы просмотрим исходный код классов Vector и ArrayList, мы заметим, что в Vector’е происходит увеличение массива вдвое, в то время как в ArrayList’е массив увеличивается на 50%. Это является ещё одним местом, где может осуществляться существенное падение производительности. Поэтому, создавая коллекцию, задумайтесь, какой именно коэффициент вместимости (инишиал кепестити) нужен коллекции, и нужен ли он вообще. Это позволит вам избежать дополнительных расходов при расширении массива.

Реализация

Обе коллекции Vector и ArrayList являются хорошим решением при индексировании данных, извлечении элементов с определённой позиции, а так же при добавлении/удалении элемента в/из конец/конца списка. Если вы хотите добавлять/удялать элементы в начале либо в середине списка, используйте LinkedList. Этот класс позволяет добавлять либо удалять элементы с любых позиций за фиксированное время O(1). Однако индексирование в LinkedList обойдётся вам дороже чем в Vector/ArrayList по времени и определяется как O(i), где i – индекс элемента.

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

Источник: JavaWorld