среда, 12 ноября 2014 г.

Подготовка к OCA. Важные фишки. Часть 1.

Кто много пишет в одном посте, рискует быть недочитанным. Поэтому я решила разбить на части.
  • В одном файле можно объявлять сколько один или несколько классов и интерфейсов. Но есть один  нюанс. Если хоть один класс или интерфейс (а больше чем 1 и нельзя) объявлен как public, то файл должен иметь название точно такое же как название этого public класса или интерфейса, иначе ошибка компиляции в стиле:

Multiple.java:1: error: class Printable is public, should be declared in a file named Printable.java
public interface Printable {
       ^
1 error
  •  В объявлении ф-ции main  модификаторы public и static можно менять местами.
  •  Класс, который принадлежит дефолтному пакету, можно использовать в других классах дефолтного пакета, если они находятся в одной и той же директории. Класс из дефолтного пакета нельзя импортировать в класс, который находится в именованном пакете.
  • Protected члены родительского класса не доступны в производном, если доступ к ним, осуществляется через создание экземпляра родительского класса через new. 
  • Интерфейс не может быть final. Интерфейс неявно является абстрактным, и добавление к нему final вызовет ошибку компиляции.
  • Статические переменные и методы наследуются дочерними классами, для них нельзя сделать переопределение в полном смысле, но можно определить такой же метод, но тут не будет ничего общего с полиморфизмом времени выполнения. 
  • char тип  - unsigned. 
  • Когда Вы используете явное преобразование типов, и пытаетесь преобразовать значение большего размера, чем вмещает тип данных, то Вы говорите компилятору, что знаете, что делаете, поэтому компилятор отрезает лишние биты, которые не влазят в меньший диапазон типа данных.
  • В идентификаторах нельзя использовать '-' символ.
  • В стеке хранятся примитивные типы и ссылки. Объекты хранятся в куче.

вторник, 5 августа 2014 г.

Как выбрать настольную лампу

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

Так как глаза и так в плачевном состоянии, а времени за компьюетором я провожу не мало, то цена лампы не имеет значения.

Для начала небольшой словарик, так как в онлайн-конструкторах по подборке ламп часто пишут умные слова и не расшифровывают.

Диммируемость - возможность регулирования интенсивности светового потока. 

Итак. Первый претендент.

1)  Pulsar . Такая лампочка есть у знакомых. Насколько я понимаю, вот это самая крутая конфигурация этой лампочки. Она существует только в двух цветах (черном и белом), классика hi-tech)). 3 режима освещения, 5 уровней яркости. 3D - регулировка. Часы, будильник и термометр. Средний срок службы  - 30 000 часов. Страна производитель - Китай.




2) Diasonic . В отличик от Pulsar, который предоставляет 3 режима освещения с температурами 2700/4200/6500, здесь мы получаем более узкий диапазон температур от 5800-6800, + предоставляет возможность длдя зардки iphone, ipod ( на мой взгляд, вещь не особо нужная, тем более обладателю android-устройства), радио со встроенными колонками, блютуз. Цветовые решения  - черный/белый. Средний срок службы - 40 000 часов. Зато есть один солидный плюс : страна производитель - Корея.  



3) Philips Eyecare . Добавлена скорее для количества.Вес неадекватный - порядка 3 кг (для сравнения Diasonic - 1 кг). Плюшек нет. Срок службы  - 15 000 часов.




Вывод: на данный момент я сколняюсь к Pulsar, так как он выглядит объективно лучше как с точки зрения базовой функциональности, так и актуальности доп плюшек. Буду признательна, если кто-то поделится новыми интересными моделями эргономичных настольных ламп. 

вторник, 1 июля 2014 г.

Java модификаторы доступа


Что-то я стала сомневаться по поводу двух модификаторов доступа: protected и default. И решила написать статью, чтобы освежить знания. В основном приходится сталкиваться с private и public.

В Java определены 4 модификатора доступа:
  • public (наименее ограничивающий доступ) (UML обозначение  - "+")
  • protected (UML обозначение  - "#")
  • default
  • private (наиболее ограничивающий доступ) (UML обозначение  - "-")

Понимание public-модификатора доступа


Public классы и интерфейсы доступны из всех пакетов, в производных и непроизводных (несвязанных) классах.

Таблица получения доступа к public классу и его членам


Понимание protected-модификатора доступа




Члены класса, объявленного с модификатором доступа protected, доступны из:
  1. Классы и интерфейсы, объявленные в том же пакете.
  2. Все производные классы, даже если они определены в различных пакетах.

Но есть тут один скользкий момент

Рассмотрим на примере (здесь оба класса расположены в пакете by.modifier):

package by.modifier;

public class ModifierTest extends PrivateModifier{
 
 public static void main(String[] args){
  new ModifierTest().modifierTest();  
 }
 
 public void modifierTest(){
     System.out.println("Test 1 " + getHello());
  
  PrivateModifier privateModifier = new PrivateModifier();
  System.out.println("Protected test " + privateModifier.getHello());
 }

}

В данном примере все хорошо, компиляция пройдет успешно


Test 1 hello
Protected test hello

С одной стороны похожий пример, но совершенно другой на самом деле (здесь ModifierTest находится в default package (здесь имеет значение только то, что это другой пакет)). То есть родитель-класс и наследник находятся в разных пакетах.

import by.modifier.PrivateModifier;
public class ModifierTest extends PrivateModifier{
 
 public static void main(String[] args){
  new ModifierTest().modifierTest();  
 }
 
 public void modifierTest(){
     System.out.println("Test 1 " + getHello());
  
  PrivateModifier privateModifier = new PrivateModifier();
  System.out.println("Protected test " + privateModifier.getHello());
 }

}

Так вот здесь мы получим интересную ошибку

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
 The method getHello() from the type PrivateModifier is not visible

 at ModifierTest.modifierTest(ModifierTest.java:15)
 at ModifierTest.main(ModifierTest.java:8)

Ошибка произошла из-за попытки доступа к protected методу класса наследника, который находится в другом пакете, через создание нового ссылочного объекта родителя.

Кратко сформулируем:
 
Класс-наследник может наследовать и получать доступ к protected-членам своего родительского класса, несмотря на то, в каком пакете он определен.
Производный класс в отличном пакете от пакета, в котором находится родительский класс, не может получать доступ к protected-переменным родительского класса, используя ссылочную переменную на родителя(новый объект-родитель).
 


Понимание default-модификатора (пакетный доступ) доступа

Члены класса, объявленные без явного указания модификатора доступа, определены с пакетным доступом. Они доступны только классам и интерфейсам объявленным в одном и том же пакете.


Подсказка

Модификатор доступа по умолчанию можно сравнить с уровнем доступа на уровне пакета (доступ только внутри пакета), а protected (защищенный доступ) можно сравнить с уровнем доступа на уровне пакета + "наследники". Наследники могут иметь доступ только, используя наследование, а не ссылку (доступ к членам класса используя оператор "." на объекте).


Понимание private-модификатора

Это самый строгий модификатор доступа. Члены класса, объявленные с модификатором private доступны только из него самого.



пятница, 27 июня 2014 г.

Подготовка к OCA и OCP

Здесь будут перечислены некоторые полезные советы при подготовке к OCP:
  1. Заниматься как минимум 15 минут каждый день, если получается больше, то тем лучше.
  2. Использовать flashcards (это такие карточки, спереди вопрос, сзади ответ).
  3. Пытаться отвечать в тесте в любом случае, потому что за это не будет никаких штрафов.
  4. Вопросы с drag-and-drop записывать на бумажку, потому что в них могут не запоминаться ответы при перепроверке.
  5. На тест отводится 3 часа на 60 вопросов, т.е. по 3 минуты на каждый.
  6. На вопросы разрешено отвечать в любом порядке.
  7. Хорошая тактика: пройти весь тест и ответить на вопросы, которые знаешь. Потом можно вернуться и доделать остальные.
  8. Будьте внимательны, читая примеры, проверяйте количество фигурных скобок, точек с запятой, скобок. Проверьте ошибки, связанные с использованием больших букв, перед тем как приступать к проверке самого кода.
  9. Время никуда не убежит. Даже если и закончится, то просто нельзя редактировать ответы и на экране появится кнопочка "Submit".

пятница, 14 февраля 2014 г.

Шпаргалка по Generic

Generic тип - это параметризированный класс или интерфейс.

Формат определения generic класса:
class name<T1, T2, ..., Tn> { /* ... */ }

Переменная типа может быть любым не примитивным типом: какой-либо тип класса, интерфейса, массива.

Тип параметра должен начинаться с большой буквы, чтобы проще было отличать от обычных параметров. Вот общепринятые названия типов, используемые в Generic:
  • E - элемент (Element)  (используется исключительно the Java Collections Framework)
  • K - ключ (Key)
  • N - число (Number)
  • T - тип (Type)
  • V - значение (Value)
  • S,U,V etc. - 2ой, 3ий, 4ый типы

Преимущества кода с использованием Generic по сравнению с кодом без Generic:
  1. Более строгая проверка типов во время компиляции.
  2. Отсутствии необходимости приведения типов.
  3. Возможность реализации общих алгоритмов, не завязанных на конкретных типах.
Сырой тип или (Raw-type) - это название Generic класса или интерфейса без каких-либо параметров.

Пример.

Box<Integer> intBox = new Box<>(); //класс Box, параметризированный Integer
                                   //это просто пример создания экземпляра класса                                   //с типом Generic

//А если дальше по коду для того же класса class Box<T> создать вот такой эземпля//р это уже будет сырой тип
Box someBox = new Box();  

Но не Generic классы или интерфейсы это не сырой тип !!!!!

Raw-типы остались для совместимости с кодом, написанным с JDK < 5 версии (с 5 версии JDK и появились Generic). Сырые типы возвращают объект типа Object.

Для обратной совместимости возможно присвоить параметризрованный тип к Raw-типу. А если наоборот, то компилятор выдаст предупреждение!!!

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;               // OK

Box rawBox = new Box();           // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;     // warning: unchecked conversion

Generic методы
Существует возможность использовать не только Generic-типы, но и generic-методы. Такими методами могут быть как статические, так и не статические методы.

public class Util {
    // Generic static method
    public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}

А вызов метода будет выглядеть вот так вот:
boolean same = Util.<Integer, String>compare(p1, p2);

Конструкторы тоже могут быть Generic и даже определять свой собственный тип параметра как в Generic, так и в не Generic классах.

class MyClass<X> {
  <T> MyClass(T t) {
    // ...
  }
}

Bounded Type Parameters (не знаю как красиво это обозвать, пусть будут параметры с ограничениями на тип)

Формат определения Bounded Type Parameter:
Тип параметра(E, или K, или N, или T и т.д.) затем слово extends и после extends "верхний" тип, то есть родительский класс, с потомками которого мы будем вызывать метод.
То есть
extends Number - значит, что мы можем использовать в качестве аргумента сам Number и все его наследники: Byte, Integer, Double, Short, Float, Long.

public class Box<T> {

    private T t;          

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public <U extends Number> void inspect(U u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("U: " + u.getClass().getName());
    }

    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        integerBox.set(new Integer(10));
        integerBox.inspect("some text"); // error: this is still String!
    }
}

Также можно использовать множественное ограничение типа.
<T extends B1 & B2 & B3>

!!!Однако следует помнить такую вещь, если мы ограничиваем тип несколькими классами и интерфейсами, то на первом месте должен следовать класс, а затем уже интерфейсы, иначе будет ошибка компиляции.
 
Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }

class D <T extends A & B & C> { /* ... */ }
class D <T extends B & A & C> { /* ... */ }  // ошибка компиляции

Также следует знать, что если объявлен метод с сигнатурой, то в него нельзя передать параметры типа Box<Integer>, потому что Box<Integer> не является наследником Box<Number>.
 
public void boxTest(Box<Number> n) { /* ... */ }

"Вкусные вещи" с Generic
Есть такая вещь, как алгоритм определения типа. Работает он так: если в методe, у которого в качестве параметра для аргумента Generic передается конкретный тип, например Integer, или же сразу при вызове явно указан возвращаемый параметр, то компилятор Java позволяет не дублировать дважды типы, на которых вызывается generic метод (все потому что существует алгоритм распознавания типа). Например: 

List<String> listOne = Collections.<String>emptyList();//можно так не извращаться
List<String> listOne = Collections.emptyList(); //а написать просто так

А вот пример, когда без "свидетеля типа" нельзя обойтись (свидетель типа, это как раз тот <String> сверху Collections.<String>emptyList(), который вносит дополнительную ясность при определении типа):
 
void processStringList(List<String> stringList) {
    // process stringList
}

processStringList(Collections.emptyList()); // в Java7 в этой строке будет ошибка                                            // компиляции

Что-то вроде List<Object> cannot be converted to List<String>. Так как компилятор требует в значение параметра аргумента T, то перебор по подборке типов он начинает с Object.
Чтобы избежать ошибки компиляции в Java 6-7, необходимо написать так
processStringList(Collections.<String>emptyList());

Wildcards (или символы подстановки)
В Generic коде может встречаться символ "?", который обозначает неизвестный тип.

 Wildcards может использоваться в качестве:
  1. параметра метода;
  2. поля;
  3. локальной переменной;
  4. иногда возвращаемым типом (однако не очень хорошо так поступать, лучше чтобы тип возвращаемого параметра был известен)
Wildscards не может использоваться в качестве:
  1. аргумента при вызове Generic метода;
  2. создании экземпляра Generic класса.
Wildcards используют 3 вида ограничений:
  1. Upperbounded (пример
    List<? extends Foo>
    ) (ограничения верхней границей - родителем, т.е. в качестве аргументов могут выступать как заданные после extends родители, так и их потомки. Отличий от Bounded Type Parameters не было замечено, разве что область применения у wildcards уже).
  2. Unbound (пример List<?>)(неограниченные символы подстановки, используется в методах класса Generic типа, функциональность, которых не привязана к этому типу)
  3. Lower Bounded Wildcards (пример <? super A>) (ограничения заданным типом или всеми типами родителями заданного типа)
Рассмотрим подробнее эти виды ограничений.

Unbound Wildcards

Существует 2 сценария, при которых Unbound Wildcards могут быть полезны:
  1. Если Вы пишите метод, для реализации которого достаточно функциональности класса Object.
  2. Когда код в методе Generic класса не зависит от параметра типа.
public static void printList(List<?> list) {
    for (Object elem: list)
        System.out.print(elem + " ");
    System.out.println();
}

List<Integer> li = Arrays.asList(1, 2, 3);
List<String>  ls = Arrays.asList("one", "two", "three");
printList(li);
printList(ls);
!!!Важно понимать,что List<?> и List<Object> это не одно и то же. Имея List<Object>, в него можно вставлять объекты типа Object или любого наследника Object. В List<?> можно вставить только null.

Lower Bounded Wildcards

Приведем пример метода, который работает с Integer, a также всеми родителями Integer (Number, Object)
public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i);
    }
}

пятница, 3 января 2014 г.

Знакомство со Stripes

Есть такой хороший фреймворк Stripes для написания веб-приложений на Java. Не так много людей, которые о нем хотя бы слышали.

Tim Fennell создал данный фреймворк в 2005 году. Он решил использовать плюшки, которые появились в Java5: аннотации, generic - и. И что самое приятное для меня, всякую конфигурацию из xml файлов.Все в Stripes нацелено на простоту. Не надо под него сильно адаптировать свой код. Он заботится о повторяющихся низкоуровневых операциях, так что разработчику остается только писать чистый, читаемый и легко поддерживаемый код.

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

  1. Умную привязку (URL, параметров и событий от HTTP к Java коду).
  2. Автозагрузка (Stripes сам заботится об автоподгрузке своих классов, без какой-либо XML конфигурации).
  3. Валидация (Stripes предоставляет мощный механизм валидации, основанный на аннотациях).
  4. Конвертация типов и форматирование (конвертация в том числе и в свои типы).
  5. Слои (за счет всего лишь 3 тегов поддержка механизма повторно используемых слоев на UI).
  6.  Локализация
  7. Обработка исключений (собственные страницы ошибок и страницы для каких-то типовых ошибок).
  8. Перехватчики (Interceptors), между request и response происходит несколько различных этапов, так вот перехватчики позволяют изменять данные на различных этапах
  9. Кастомизируемые URL (можно задать паттерн для представления URL)
  10. Легкая интеграция с AJAX (можно использовать для front-end части свой любимый ajax фреймворк, а об backend позаботится Stripes).
  11. Тестирование (Stripes создает mock объекты, что значительно облегчает процесс автоматизированного тестирования).
  12. Легкая расширяемость и возможность адаптировать  под свои нужды.
      
Если кратко описать суть работы Stripes, то каждый класс контроллер реализует интерфейс ActionBean и ему необходимо реализовать методы 

public ActionBeanContext getContext() { return ctx; }
public void setContext(ActionBeanContext ctx) { this.ctx = ctx; }

Обработчики событий (Event Handlers) выполняют всякие действия, происходящие при нажатии на ссылки или кнопки. За отсутствие наличия конфигурации приходится немного платить, это заключается в том, что к обработчикам событий предъявляются следующие требования:
  1. Они д.б. объявлены как public 
  2. Они д. возвращать объект типа Resolution
  3. Они не должны принимать параметров.
  4. Они д.б. определены в классе, реализующем интерфейс ActionBean.
Также об ограничениях как минимум один из обработчиков событий в одном Action Bean должен иметь аннотацию @DefaultHandler (за исключением если он только один в ActionBean, но его все равно всегда рекомендуется добавлять для единообразия), иначе будет исключение. Также исключение будет в том случае, если добавить аннотацию @DefaultHandler на нескольких обработчиках в одном ActionBean. 
После того, как выполнена вся работа обработчиком необходимо вернуть объект типа Resolution (разрешение), который содержит информацию о возвращаемой странице и говорит, что необходимо вернуть в ответ на текущий запрос.
Вообще, Resolution, это интерфейс, который содержит один метод

public interface Resolution {
void execute(HttpServletRequest request,
HttpServletResponse response)
throws Exception;

Существуют следующие реализации интерфейса Resolution
  1. ForwardResolution (пересылает по пути такому как JSP или другой ActionBean)
  2. RedirectResolution (тоже что и ForwardResolution, но использует перенаправление за счет клиентской стороны)
  3. StreamingResolution (направляет поток непосредственно обратно к клиенту, например создавая бинарный файл)
  4. JavaScriptResolution (конвертирует Java объект в Javascript код, который отправляется обратно на клиент и его можно расшифровать, использую Javascript функцию eval(). Это особенно полезно, когда используется Ajax).
  5. ErrorResolution (отправляет HTTP ошибку обратно на клиент, используя статус ошибки и необязательное сообщение об ошибке).
Вообщем, как-то так, я сама об этом ничего не знаю, но мне это уже как-то отдаленно напоминает смесь JSF cо Struts.

четверг, 28 ноября 2013 г.

Внедрение методов Spring

Прием внедрения методов  позволяет внедрять в компоненты определения целых методов.
Spring предоставляет Java-программистам возможность внедрения методов в Java-классы во время выполнения.

Фреймворк Spring поддерживает две формы внедрения методов:
  •  ‰ замещение  метода    – позволяет во время выполнения заместить существующий метод (абстрактный или конкретный) новой реализацией;
  •  ‰ внедрение метода чтения    – позволяет во время выполнения  заместить существующий метод (абстрактный или конкретный) новой реализацией, возвращающей определенный компонент из контекста Spring.
Пример замещения методов


<bean id="magicBox" class="com.springinaction.springidol.MagicBoxImpl">
      <replaced-method  name="getContents"  replacer="tigerReplacer" />
</bean>
<bean id="tigerReplacer" class="com.springinaction.springidol.TigerReplacer" />

Сейчас в компоненте  magicBox имеется элемент  <replaced-method> . Как следует из названия, этот элемент используется для замены метода новой реализацией. В данном случае атрибут name указывает имя замещаемого метода  getContents().

package com.springinaction.springidol;
import java.lang.reflect.Method;
import org.springframework.beans.factory.support.MethodReplacer; 
public class TigerReplacer implements MethodReplacer {
 public Object reimplement(Object target, Method method, // Подмена
          Object[] args) throws Throwable {             // метода
        return "A ferocious tiger"; // Помещает тигра в ящик
    }
}

Класс TigerReplacer реализует интерфейс  MethodReplacer, требующий реализации единственного метода  reimplement(). Этот метод принимает три аргумента: объект, в котором будет производиться замещение метода, метод, подлежащий замещению, и массив аргументов, принимаемых методом.
Тело метода  reimplement() фактически становится новой реализацией метода  getContents().

Способ применения:
Прием внедрения метода с успехом может использоваться, когда фактическая реализация замещаемого метода не известна до момента развертывания. К этому моменту класс с замещающей реализацией метода можно оформить в виде JAR-файла и поместить его в библиотеку классов (classpath) приложения. 

Пример внедрения метода чтения

Внедрение    через метод чтения – это особый случай внедрения методов, когда объявляется метод (обычно абстрактный), возвращающий компонент определенного типа, но фактически возвращаемый компонент определяется в контексте Spring.

package com.springinaction.springidol;
public abstract class Instrumentalist implements Performer {
    public Instrumentalist() {}
    public void perform() throws PerformanceException {
        System.out.print("Playing " + song + " : ");
        getInstrument().play();   // Используется внедряемый метод
    }                        // getInstrument()
    private String song;
    public void setSong(String song) {
        this.song = song;
    }
    public abstract Instrument getInstrument(); // Внедряемый метод

}

Для поддержки внедрения методов чтения фреймворк Spring предлагает элемент  <lookup-method> . Как и  <replaced-method>, элемент <lookup-method> замещает существующий метод новой реализацией во время выполнения. 

<bean id="stevie" class="com.springinaction.springidol.Instrumentalist">
  <lookup-method name="getInstrument" bean="guitar" />
  <property name="song" value="Greensleeves" />
</bean>

Как и в элементе  <replaced-method>, атрибут  name элемента  <lookup-method> определяет замещаемый метод. Здесь замещается метод getInstrument(). Атрибут  bean определяет компонент, возвращаемый методом getInstrument().

Важно помнить, что при использовании элемента  <lookup-method> для внедрения метода чтения совсем необязательно, чтобы замещаемый метод был методом чтения (то есть методом, имя которого начинается со слова  get). С помощью элемента  <lookup-method> можно заместить любой метод, возвращающий некоторое значение.

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