среда, 30 октября 2013 г.

Сертификация Java SE 7 Programmer I 1Z0-803

В этой статье напишу о том, на том что нужно обратить внимание, если вы собрались сдать сертификацию 1Z0-803.
Сразу предупрежу, что эта статья будет вряд ли интересна людям, имеющим достаточный опыт в java. Пишу ее больше для новичков.
Сейчас прохождение этой сертификации обязательно для следующего уровня - Java SE Professional. Так что, чтобы сдать Professional, придется сдавать и Associate.


Основы языка

Ключевые слова в Java:
abstract default goto package this assert do if
private throw boolean double implements protected
throws break else import public transient byte enum
instanceof return true case extends int short try
catch false interface static void char final long
strictfp volatile class finally native super while
const float new switch continue for null synchronized
Тут стоит обратить внимание на то, что ни одно из ключевых слов НЕ написано camelCase-ом.
По невнимательности можно спутать instanceof с instanceOf, который вызовет ошибку компиляции.

Структура Java файла

В одном java файле может быть только один public класс или интерфейс. И имя этого public класса/интерфейса должно совпадать с именем файла.

import-ы

Классы из пакета по умолчанию(default, no-name package) недоступны из других пакетов(не default) и импортировать их в эти классы нельзя.

В класс можно два раза импортировать один и тот же класс/пакет. Такой код не вызовет ошибок:
import java.util.List;
import java.util.List;
Нужно быть внимательным. Вот такой код вызовет ошибку компиляции:
import java.util;

В java есть возможность импортировать статические методы и поля класса, например можно импортировать всю статику:
import static java.lang.Math.*;

Сигнатура main метода

public static void main(String[] args0)
public static void main(String args1[])
public static void main(String...args2) 
Тут нужно быть внимательным. В вопросах могут быть забыты [] или какой-то из модификаторов.
main метод должен быть public, static, возвращать void и принимать одномерный массив строк.

Параметры командной строки

java NameOfClass paramX paramY paramZ
Эти вопросы тоже на внимательность. Часто в main методе выводится значение args[1]. В данном случае args[1] = "paramY".

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

Nonaccess modifiers

В этом экзамене будут только следующие модификаторы abstract, final, static. Нужно знать что они означают и как применяются к классам, методам и полям класса.

Типы данных

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Все целочисленные литералы в java имеют тип int. Литералы с плавающей точкой тип double.
Из-за этого:
long i = 10; //ОК Автоматически скастится, т.к. long шире чем int.
float f = 10; //ОК Автоматически скастится.
float f1 = 10.0; //Compilation error. Т.к. в переменную типа float пытаемся присвоить double.
int i0 = 'A'; //ОК Автоматически скастится.

При выполнении арифметических и побитовых преобразований значения byte, short и char расширяются до int:
byte b1 = 1;
byte b2 = 2;
byte b3 = b1 + b2; //Compilation error. Результатом будет int.
В данном случаем можно использовать явное преобразование типов byte b3 = (byte) (b1 + b2);

Префиксы для литиралов в других системах исчисления: 0 - восьмеричная, 0x - шеснадцатиричная, 0b - бинарная.
Суффиксы для литералов l или L - long, F или f - float, D или d - double. Нужно помнить, что суффикс D есть. На практике он ни когда не используется, т.к. по умолчанию литералы с плавающей точкой - double.
scientific notation
double d = 1,234e2; // Тоже самое что и 123,4

Использование подчеркиваний в литералах

Честно скопипащу ибо переводить не вижу смысла, да и на английском понятнее:
  • You can’t start or end a literal value with an underscore.
  • You can’t place an underscore right after the prefixes 0b, 0B, 0x, and 0X, which are used to define binary and hexadecimal literal values.
  • You can place an underscore right after the prefix 0, which is used to define an octal literal value.
  • You can’t place an underscore prior to an L suffix (the L suffix is used to mark a literal value as long).
  • You can’t use an underscore in positions where a string of digits is expected.


Нужно быть внимательнее с boolean и if.
В вопросах попадается такое:
boolean b = true;
if (b = false) {
 //Код
}

Нужно знать, что java кэширует значения для строк и для оберток целочисленных примитивов.
Для целых чисел кэшируются только значения от -128 до 127. Подробнее смотрите реализацию метода valueOf.
Кому интересно про кеширование строк, почитайте про метод String.intern().
Кэшироваться будут значения присвоенные с помощью литералов.
Если объект создается в рантайме, то кэшироваться он не будет.
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = new Integer(100);
System.out.println(i1 == i2);  //true
System.out.println(i1 == i3);  //false
Integer i4 = 128;
Integer i5 = 128;
System.out.println(i4 == i5);  //false

String s1 = "s";
String s2 = "s";
String s3 = new String("s");
System.out.println(s1 == s2); //true
System.out.println(s1 == s3); // false
Вопросы на это (по крайней мере на строки) в тесте есть.

Приоритет операторов


Унарные операции. Достаточно часто попадаются в вопросах экзамена.
int i=0;
System.out.println(i++); //0
i=0;
System.out.println(++i); //1
i=0;
System.out.println(i+=1); //1
// i+=1 почти shortcut для i=i+1; Почему почти - http://stackoverflow.com/questions/8710619/java-operator
//Аналогично
System.out.println(i=5); //5

c = a-- + ++b; //OK
c = a--+++b;   //Compilation error
c = a--+--b;   //OK
Про этот Compilation error своими словами: Приоритетней postfix операция над prefix. Когда компилятор видит два подряд знака (например ++) он знает куда их применить. Когда 3 знака (+++), то первые 2 знака применяются к левому операнду, т.е postfix. А левого операнда нет. Ошибка будет такая:
java: unexpected type
  required: variable
  found:    value   
Но таких вопросов с тремя подряд плюсами на Associate я не встречал. На экзамене везде в подобных вопросах стояли пробелы там, где это нужно.
Еще пример для понимания:
int a = 100;
int b = 10;
System.out.println(a+++b); //110

Тут тоже все хорошо:
c=-a;

Еще один из вопросов на внимательность:
public class StartClass {
    public static void main(String[] args) {
        int x = 0;
        int y = 0;
        for (int z = 0; z < 5; z++) {
            if ((++x > 2) || (++y > 2)) {
                x++;
            }
        }
        System.out.println(x + " " + y);
    }
}

При использовании логических операций && и || правая часть выражения может не выполняться. За этим нужно следить, когда в правой части используется унарные операции.
Стоит помнить и про побитовые & и | при использовании с boolean. Правая часть всегда выполнится. На экзамене мне такие вопросы не попадались.

Нужно понимать как работают переменные, которые являются ссылками на объекты. Понимать что такое mutable и immutable объекты в java. Особенно это касается класса String и оберток для примитивов.

Методы, поля, конструкторы класса

class Employee {
 Employee() {
  System.out.println("Employee:constructor");
 }
 {
  System.out.println("Employee:initializer");
 }
}
class TestEmp {
 public static void main(String args[]) {
 Employee e = new Employee(); //Employee:initializer  Employee:constructor
 }
}

Нужно помнить, что блок инициализации выполняется раньше конструктора.
Нужно различать конструктор по умолчанию и конструктор без параметров. На экзамене попадаются вопросы про это.
При наследовании в конструкторе вашего класса неявно первой строчкой будет вызван конструктор без параметров класса родителя (если он там есть). Либо вы сами можете первой строчкой вызвать другой конструктор родительского класса через super. Также первой строчкой в конструкторе можно вызвать перегруженный конструктор через this.

Еще с конструкторами нужно быть внимательными:
public class Main() {
 void Main() {} //Это не конструктор! Это метод.
}

Поля класса будут инициализированным значениями по умолчанию.

Переменные, объявленные внутри функции и используемые далее в коде, должны быть обязательно инициализированы. Причем инициализация не обязательно должна быть при объявлении переменной. Например, такой код скомпилируется:
int i;
if (условие) {
 i = 0;
} else {
 i = 1;
}
Такой кусок код тоже скомпилируется:
public static void main(String[] args) {
    int i;
    System.out.println("string");
}

А такой НЕТ:
public static void main(String[] args) {
    int i;
    boolean b = true;
    if (b) {
        i = 0;
    }
    System.out.println(i);
}

Попадаются такие вопросы: Нужно определить на какое количество объектов указывают ссылки в определенный момент выполнения кода.

Сигнатурой метода является его имя и параметры. Возвращаемое значение в сигнатуру не входит.
Поэтому в классе не может быть 2-х методов с одной сигнатурой.
Например, такой код не скомпилируется:
class A {
 void method(int i) {}
 int method(int i) {return i;}
}

Перегрузка методов

public class Main {

    public static void method(int a) {
        System.out.println("int");
    }

    public static void method(Integer a) {
        System.out.println("Integer");
    }

    public static void method(long a) {
        System.out.println("long");
    }

    public static void method(Long a) {
        System.out.println("Long");
    }

    public static void method(byte... a) {
        System.out.println("byte array");
    }

    public static void main(String[] args) {
        byte b = 0;
        method(b);
    }
}
Будет напечатан int. Приоритет такой: примитивы, обертки, массивы. Вызваемый метод определяется в момент компиляции.

Нужно знать какие методы есть у String, StringBuilder, List.
Нужно помнить что у StringBuilder не переопределены методы equals и hashCode.
Нужно знать сигнатуру методов equals и hashCode. Могут попадаться похожие методы, которые вызовут ошибку компиляции либо дадут совсем другой результат.
Много вопросов попадаются на инициализацию массивов в java.
long нельзя использовать в switch. Можно только byte, char, short, int и String. И обертки этих примитивов.

Наследование

При наследовании поля класса скрываются. Методы перекрываются.
Какой метод будет вызван на объекте определяется в рантайме. При обращении к полю, поле какого класса будет использовано определяется во время компиляции.
Пример:
class A {
    int field = 1;
    void method() {
        System.out.println("A" + field);
    }

    public static void main(String[] args) {
        A b = new B();
        System.out.println(b.field);
        b.method();
    }
}

class B extends A {
    int field = 2;
    void method() {
        System.out.println("B" + field);
    }
}
Результат:
1
B2

При наследовании можно увеличивать область видимости: default -> protected -> public
class A {
    void method() {
    }
}

class B extends A {
    protected void method() {
    }
}

Приведение типов

interface MyInterface{}
public class Main {    
    public static void main(String[] args) {
        MyInterface var1 = (MyInterface)new Main(); //OK
        MyInterface my = new MyInterface(){};
        Main var2 = (Main) my; //OK MyInterface - просто интрефейс. Он может быть реализован любым наследником Main. Поэтому кастить можно. В рантайме будет ошибка.
        Main var3 = (Main) new MyInterface(){}; //Compilation error
    }
}
Таких сложных вопросов на экзамене я не видел. Но видел в тесте в одной из книг.

Также среди вопросов есть вопросы на инкапсуляцию и полиморфизм. Где среди нескольких перечисленных вариантов нужно выбрать пару попадающих под определение инкапсуляции или полиморфизма.

Ошибки

Тут нужно понимать чем отличатся checked и unchecked exceptions, понимать что такое Error и что некоторые error-ы в принципе можно поймать блоком catch.

Есть вопросы про порядок блоков try/catch/finally  - порядок именно такой.
Нужно помнить, что блок catch или finally может отсутствовать, и что finally выполняется всегда.

Нужно понимать, что такой код не скомпилируется:
try {
    //код
} catch(Exception e) {   
} catch(NullPointerException e) {
}

Если в сигнатуре метода указано, что он бросает исключение, то в классах наследниках в сигнатуре переопределенного метода может быть указан только этот же Exception или наследники этого Exception-а, либо Exception может быть не указан. Но это правило действует только для checked Exception-ов.
Для RuntimeException в аналогичном случае такое правило не действует.

Вопросов на try with resources и multi-catch мне не попалось.

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

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

При подготовке советую читать Mala Gupta OCA Java SE 7 Programmer I Certification Guide. Этой книги достаточно. Экзамен в принципе простой для людей имеющих несколько лет разработки на java. Просто нужно освежить некоторые моменты. Всем удачи )

Комментариев нет:

Отправить комментарий