Рубрики
Без рубрики

Сертификация OCP – Усовершенствованный Дизайн класса Java

Узнайте несколько советов по общим аспектам сертификационного экзамена OCP.

Автор оригинала: baeldung.

1. Обзор

В этом учебном пособии мы обсудим цель разработки расширенного класса Java для сертификации OCP.

2. Сертификация OCP Java

Сертификация OCP является обновлением сертификации OCA , но соответствует тому же формату вопросов с множественным выбором. Однако он включает в себя расширенные темы, такие как параллелизм, универсальные решения и NIO.

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

Каждый из следующих разделов посвящен какой-либо цели экзамена.

3. Разработайте код, использующий Абстрактные классы и методы

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

Совет по экзамену 3.1: Неверный модификатор доступа с абстрактными классами

Мы всегда должны искать модификатор доступа в вопросах о абстрактных классах и методах.

Например, попробуйте решить следующие задачи:

package animal;
public abstract class Animal {
    
    abstract boolean canFly();
}
    
package horse;
import animal.Animal;

public class Horse extends Animal {
    
    @Override
    boolean canFly() {
        return false;
    }
    
    public static void main(String[] args) {
    
        System.out.println(new Horse().canFly());
    }    
}
Which of the following is true?
A. The output is false
B. Compilation fails on Line 10
C. Compilation fails on Line 12
D. None of the above

Примечательно, что метод abstract имеет модификатор доступа по умолчанию, и, поскольку оба класса находятся в разных пакетах, мы не можем получить к нему доступ в Horse классе . Следовательно, правильный ответ (B).

Совет по экзамену 3.2: Синтаксические ошибки в абстрактном классе или методе

Некоторые вопросы требуют, чтобы мы проверили неправильный синтаксис в данном коде. С помощью абстрактных классов мы можем легко пропустить такие ошибки.

Например, попробуйте решить следующие задачи:

public abstract class Animal {
  
    protected abstract boolean canFly() {
    }
  
    public abstract void eat() {
        System.out.println("Eat...");
    }
}
  
public class Amphibian extends Animal {
    @Override
    protected boolean canFly() {
        return false;
    }
  
    @Override
    public void eat() {
  
    }
  
    public abstract boolean swim();
}
  
public class Frog extends Amphibian {
}
Which are true? (Choose all that apply.)
A. Compilation error on line 3
B. Compilation error on line 6
C. Compilation error on line 11
D. Compilation error on line 13
E. Compilation error on line 22

Здесь важно помнить, что абстрактные методы не могут иметь тело метода . Кроме того, абстрактный метод не может существовать в не/| абстрактном классе . Следовательно, (А), (Б) и (В) являются правильными ответами.

Совет по экзамену 3.3: Отсутствует реализация абстрактных методов

Ищите не абстрактные дочерние классы без конкретной реализации для абстрактного метода.

Например, попробуйте решить следующие задачи:

public abstract class Animal {
  
    protected abstract boolean canFly();
  
    public abstract void eat();
}
 
public abstract class Amphibian extends Animal {
  
    @Override
    public void eat() {
        System.out.println("Eat...");
    }
  
    public abstract boolean swim();
}
  
public class Frog extends Amphibian {
  
    @Override
    protected boolean swim() {
        return false;
    }
  
}
Which are true? (Choose all that apply)
A. Compilation error on line 8
B. Compilation error on line 11
C. Compilation error on line 18
D. Compilation error on line 21
E. No compilation error

Лягушка класс не реализует может летать() метод , а также уменьшает видимость плавать() метод . Следовательно, (C) и (D) являются правильными.

Несмотря на то, что Амфибия не реализует может летать (), он объявлен как абстрактный класс, поэтому (A) неверно.

Совет по экзамену 3.4: Используйте частное, окончательное или статическое ключевое слово с абстрактным ключевым словом

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

public final abstract class Animal {
}

public abstract class Animal {

    public final abstract void eat();
}

public abstract class Animal {

    private abstract void eat();
}

Любое такое объявление приведет к ошибке компиляции.

4. Разработайте Код, в котором используется последнее Ключевое слово

Ключевое слово final в Java позволяет нам объявлять переменные с постоянным значением. Более того, это также позволяет нам объявлять классы и методы, которые мы не можем расширить или переопределить.

Совет по экзамену 4.1: Переопределенные итоговые классы или методы

Ищите методы, которые объявлены как final, и переопределены в дочернем классе.

Например, попробуйте решить следующие задачи:

public abstract class Animal {
  
    public final void eat() {
        System.out.println("Eat...");
    }
}
  
public class Horse extends Animal {
  
    public void eat() {
        System.out.println("Eat Grass");
    }
  
    public static void main(String[] args) {
        Animal animal = new Horse();
        animal.eat();
    }
}
What is the output?
A. Eat...
B. Eat Grass
C. The code will not compile because of line 3
D. The code will not compile because of line 8
E. The code will not compile because of line 10

Поскольку eat() объявлен как окончательный в классе Animal , мы не можем переопределить его в классе Horse /. Следовательно, (E) является правильным ответом.

Кроме того, найдите переменные final в аргументе метода. Если таким переменным будет присвоено новое значение, это приведет к ошибке компиляции.

5. Внутренние Классы

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

Совет по экзамену 5.1: Неправильное создание экземпляров нестатических внутренних классов

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

Например, попробуйте решить следующие задачи:

public class Animal {

    class EatingHabbits {
    }

    private EatingHabbits eatingHabbits() {
        return new EatingHabbits();
    }
}

public class Zookeeper {

    public static void main(String[] args) {
        Zookeeper zookeeper = new Zookeeper();
        zookeeper.feed();
    }

    private void feed() {
        EatingHabbits habbits = new EatingHabbits();
        Animal animal = new Animal();
        Animal.EatingHabbits habbits1 = animal.eatingHabbits();
    }
}
What is the result? (Choose all that apply.)
A. Compilation error on line 7
B. Compilation error on line 19
C. Compilation error on line 21
D. No compilation error

Поскольку в строке 19 мы пытаемся создать экземпляр внутреннего класса без объекта внешнего класса, (B) является правильным ответом.

Совет по экзамену 5.2: Неправильное использование этого ключевого слова во внутренних классах

Ищите неправильное использование этого ключевого слова внутри внутренних классов:

public class Animal {
    private int age = 10;

    public class EatingHabbits {
        private int numOfTimes = 5;

        public void print() {
            System.out.println("The value of numOfTimes " + this.numOfTimes);
            System.out.println("The value of age " + this.age);
            System.out.println("The value of age " + Animal.this.age);
        }
    }

    public static void main(String[] args) {
        Animal.EatingHabbits habbits = new Animal().new EatingHabbits();
        habbits.print();
    }
}

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

Совет По Экзамену 5.3: Не окончательные Переменные Внутри Локальных Внутренних Классов

Локальные классы методов не могут получить доступ к локальной переменной, если она не объявлена как final или ее значение не остается неизменным внутри внутреннего класса.

Например, попробуйте решить следующие задачи:

public class Animal {
    private int age = 10;

    public void printAge() {
        String message = "The age is ";
        class PrintUtility {
            void print() {
                System.out.println(message + age);
            }
        }

        PrintUtility utility = new PrintUtility();
        utility.print();
    }

    public static void main(String[] args) {
        new Animal().printAge();
    }
}
What is the result of the following code?
 
A. The age is 0
B. The age is 10
C. Line 8 generates a compiler error
D. Line 12 generates a compiler error
E. An exception is thrown

Поскольку мы никогда не обновляли поле сообщение , оно фактически окончательное . Следовательно, (B) является правильным ответом.

Совет по экзамену 5.4: Локальный внутренний класс не может быть помечен как частный, общедоступный, защищенный или статический

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

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

Совет по экзамену 5.5: Нестатические переменные-члены в статическом внутреннем классе

s статические вложенные классы не имеют доступа к переменным экземпляра или не статическим методам внешнего класса.

Поэтому важно обращать внимание на вопросы, которые включают статические вложенные классы, но ведут себя как не статические вложенные классы:

public class Animal {

    private int age = 10;

    static class EatingHabits {

        private int numOfTimes = 5;

        public void print() {
            System.out.println("The value of x " + age);
            System.out.println("The value of x " + Animal.this.age);
            System.out.println("The value of numOfTimes " + numOfTimes);
        }
    }
}

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

Совет по экзамену 5.6: Неверное объявление для анонимных внутренних классов

Анонимные классы разбросаны по экзамену OCP так же, как и вложенные классы. Существует множество вопросов, касающихся коллекций, потоков и параллелизма, в которых используется анонимный внутренний класс, в основном с запутанным синтаксисом.

Например, попробуйте решить следующие задачи:

public class Animal {

    public void feed() {
        System.out.println("Eating Grass");
    }
}

public class Zookeeper {

    public static void main(String[] args) {
        Animal animal = new Animal(){
            public void feed(){
                System.out.println("Eating Fish");
            }
        }
        animal.feed();
    }
}
What is the result?
 
A. An exception occurs at runtime
B. Eating Fish
C. Eating Grass
D. Compilation fails because of an error on line 11
E. Compilation fails because of an error on line 12
F. Compilation fails because of an error on line 15

Поскольку анонимный класс Animal не закрывается точкой с запятой , в строке 15 имеется ошибка компиляции, поэтому (F) является правильным ответом.

Совет по экзамену 5.7. Создание экземпляра интерфейса

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

Runnable r = new Runnable(); // compilation error

Runnable r = new Runnable() { // legal statement
    @Override
    public void run() {
    
    }
};

6. Перечисления

Перечисления-это способ представления перечисляемого списка констант в Java. Они ведут себя как обычные классы Java и, следовательно, могут содержать переменные, методы и конструкторы .

Несмотря на схожесть, перечисления имеют довольно сложный синтаксис, чем обычные классы. Экзамены OCP фокусируются на таких синтаксических неопределенностях с вопросами, содержащими перечисления.

Совет по экзамену 6.1: Синтаксические ошибки в объявлении перечисления

Обратите внимание на объявления перечисления с неправильными синтаксическими ошибками.

Например, попробуйте решить следующие задачи:

public enum AnimalSpecies {
    MAMMAL(false), FISH(true), BIRD(false),
    REPTILE(false), AMPHIBIAN(true)

    boolean hasFins;

    public AnimalSpecies(boolean hasFins) {
        this.hasFins = hasFins;
    }

    public boolean hasFins() {
        return hasFins;
    }
}
What is the result of the following code? (Choose all that apply.)
 
A. Compiler error on line 2
B. Compiler error on line 3
C. Compiler error on line 7
D. Compiler error on line 11
E. The code compiles successfully

В этом вопросе есть две проблемы:

  • В строке 3 отсутствует точка с запятой (;). Помните, что если перечисление содержит переменные или методы, точка с запятой обязательна
  • В этом перечислении есть открытый конструктор

Следовательно, (B) и (C) являются правильными ответами.

Совет по экзамену 6.2: перечисление с абстрактными методами

Обратите внимание на перечисление вопросов, которые реализуют интерфейс или содержат абстрактный метод.

Например, попробуйте решить следующие задачи:

public enum AnimalSpecies {
    MAMMAL(false), FISH(true){
        @Override
        boolean canFly() {
            return false;
        }
    }, BIRD(false),
    REPTILE(false), AMPHIBIAN(true);

    boolean hasFins;

    AnimalSpecies(boolean hasFins) {
        this.hasFins = hasFins;
    }

    public boolean hasFins() {
        return hasFins;
    }

    abstract boolean canFly();
}

public class Zookeeper {

    public static void main(String[] args) {
        AnimalSpecies.MAMMAL.canFly();
    }
}
What is the result of the following code? (Choose all that apply.)
  
A. Compilation error on line 2
B. Compilation error on line 4
C. Compilation error on line 20
D. Compilation error on line 26
E. No compilation error

Поскольку существует абстрактный метод, мы должны обеспечить его реализацию для каждой перечисления константы. И поскольку приведенный выше код реализует его только для FISH , мы получим ошибку компиляции. Следовательно, (А) является правильным ответом.

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

Совет по экзамену 6.3: Повторение значений перечисления

Java предоставляет статические методы для перебора значений перечисления . Мы должны ожидать вопросов, которые попросят нас рассчитать результат одной такой итерации.

Например, попробуйте решить следующие задачи:

public enum AnimalSpecies {
    MAMMAL, FISH, BIRD, REPTILE, AMPHIBIAN
}

public class Zookeeper {

    public static void main(String[] args) {
        AnimalSpecies[] animals = AnimalSpecies.values();
        System.out.println(animals[2]);
    }
}
What is the result? (Choose all that apply.)
 
A. FISH
B. BIRD
C. Compilation fails due to an error on line 2
D. Compilation fails due to an error on line 8
E. Compilation fails due to an error on line 10

Вывод ПТИЦА , следовательно, (B) является правильным.

7. Интерфейсы и @Переопределение в Java

В Java интерфейсы-это абстрактные типы, которые определяют контракт для класса. Экзамен OCP содержит различные вопросы, которые проверяют кандидата на наследование, переопределение методов и проблемы множественного наследования.

Совет по экзамену 7.1: Реализация абстрактного метода в неабстрактных классах

Обратите внимание на конкретные реализации, которые не реализуют все абстрактные методы интерфейса.

Например, попробуйте решить следующие задачи:

class Bird implements Flyable {
    public void fly() {
    }
}
  
abstract class Catbirds extends Bird {
  
}
  
abstract class Flamingos extends Bird {
    public abstract String color();
}
  
class GreaterFlamingo extends Flamingos {
    public String color() {
        System.out.println("The color is pink");
    }    
}
  
interface Flyable {
    void fly();
}
What is the result? (Choose all that apply.)
 
A. Compilation succeeds
B. Compilation fails with an error on line 6
C. Compilation fails with an error on line 10
D. Compilation fails with an error on line 11
E. Compilation fails with an error on line 14

Поскольку все это верные утверждения, (А) является правильным ответом.

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

Другая такая ошибка компиляции возникает из-за использования реализует и расширяет:

interface Bird extends Flyable, Wings {}
 
public class GreaterFlamingo extends Flamingos implements Bird, Vegetarian {}
 
public class GreaterFlamingo extends Flamingos, Bird {}

Здесь строки 1 и 3 являются допустимыми утверждениями, в то время как 5 не допускается в Java. Класс Greater Flamingo в строке 3 теперь должен предоставлять конкретные реализации всех абстрактных методов.

Совет по экзамену 7.2: Методы по умолчанию с идентичными сигнатурами методов

Начиная с JDK 8, интерфейсы теперь могут иметь статические методы и методы по умолчанию . Это может привести к ситуации, когда несколько интерфейсов содержат метод по умолчанию с одной и той же подписью. Мы найдем вопросы на экзамене с такими интерфейсами.

Например, попробуйте решить следующие задачи:

public interface Vegetarian {

    default void eat() {
        System.out.println("Eat Veg");
    }
}

public interface NonVegetarian {

    default void eat() {
        System.out.println("Eat NonVeg");
    }
}

public class Racoon implements Vegetarian, NonVegetarian {

    @Override
    void eat() {
        System.out.println("Eat Something")
    }

    public static void main(String[] args) {
        Racoon racoon = new Racoon();
        racoon.eat();
    }
}
What is the result?
 
A. Eat Veg
B. Eat NonVeg
C. Eat Something
D. The output is unpredictable
E. Compilation fails
F. An exception is thrown at runtime

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

Теперь, поскольку этот код действительно обеспечивает реализацию метода eat () , поначалу он может показаться допустимым кодом. Однако, если мы присмотримся повнимательнее, то увидим, что переопределенный метод eat() не является общедоступным. Следовательно, правильный ответ (E).

Совет по экзамену 7.3: Использование @Переопределения

@Override используется для обозначения переопределенного метода в Java. Хотя это необязательно, это улучшает читабельность и помогает компилятору сообщать о неправильных синтаксисах. Поищите неправильное использование этой аннотации на экзамене.

Например, попробуйте решить следующие задачи:

public abstract class Flamingo {

    public abstract String color();

    public abstract void fly();
}

public class GreaterFlamingo extends Flamingo {
    @Override
    public String color() {
        return "Pink";
    }

    @Override
    public void fly() {
        System.out.println("Flying");
    }

    @Override
    public void eat() {
        System.out.println("Eating");
    }
    
    public static void main(String[] args) {
        GreaterFlamingo flamingo = new GreaterFlamingo();
        System.out.println(flamingo.color());
    }
}
What is the result? (Choose all that apply.)
 
A. Pink
B. Compilation error on line 8
C. Compilation error on line 19
D. Compilation error on line 20

Пожалуйста, обратите внимание, что мы использовали @Переопределение в методе eat () . Однако, поскольку в классе Flamingo нет такого абстрактного метода, это не переопределенный метод. Следовательно, (C) является правильным ответом.

8. Создавайте и используйте Лямбда-выражения

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

Синтаксис лямбда-выражения немного сложен. Чтобы выявить синтаксические ошибки на экзамене, важно понять некоторые правила, касающиеся лямбд .

Совет по экзамену 8.1: Не окончательные Переменные Внутри Лямбда-Объявлений

Подобно локальным классам методов, мы можем использовать final или эффективно final переменные только внутри лямбда-функции. Экзаменационные вопросы могут не соответствовать таким ограничениям.

Например, попробуйте решить следующие задачи:

List birds = Arrays.asList("eagle", "seagull", "albatross", "buzzard", "goose");
int longest = 0;
birds.forEach(b -> {
    if (b.length() > longest){
        longest = b.length();
    }
});
 
System.out.println("Longest bird name is length: " + longest);
What is the result?

A. "Longest bird name is length: 9"
B. Compilation fails because of an error on line 3
C. Compilation fails because of an error on line 5
D. A runtime exception occurs on line 5

Это приведет к ошибке компиляции, поскольку мы попытались присвоить значение переменной внутри лямбда-выражения . Следовательно, (C) является правильным ответом.

9. Заключение

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

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

И, конечно, лучший способ взломать экзамен-это заранее попрактиковаться в таких шутливых вопросах!