Advanced Class Design & Design Patterns practice questions

From OCP Java SE 8 (1Z0-809) · 25 questions on this topic

Advanced Class Design & Design Patterns practice questions from OCP Java SE 8 (1Z0-809). This pack has 25 questions tagged Advanced Class Design & Design Patterns, drawn from its timed mock exams. 8 of them are worked through in full below — the question, every option, why each is right or wrong, and the explanation.

Worked examples for Advanced Class Design & Design Patterns

  1. Question 1

    What is the output of the following program? ```java public class Main { static class Box { String label() { return "boxed"; } } public static void main(String[] args) { Box b = new Box(); System.out.println(b.label()); } } ```

    1. A. An exception is thrown at runtime

      Nothing in the code throws; construction and the method call are routine.

    2. B. boxedCorrect answer

      Correct: the nested class is instantiated directly and its instance method returns this string.

    3. C. Compilation fails because static classes cannot have instance methods

      Static nesting refers to the class not capturing an outer instance; it says nothing against declaring instance methods.

    4. D. Compilation fails because Box needs an enclosing instance

      Requiring an enclosing instance is the rule for non-static member (inner) classes, not static ones.

    Explanation

    A static nested class is an independent type that merely lives inside another; it needs no enclosing instance and can hold ordinary instance methods. Constructing it with new and calling its method behaves like any top-level class.

  2. Question 2

    What is the result of compiling the following program? ```java public class Main { public static void main(String[] args) { class Local { static int counter = 0; } System.out.println(Local.counter); } } ```

    1. A. Compilation failsCorrect answer

      Correct: a local class may not declare a mutable static field; only static final compile-time constants are allowed, so this is rejected.

    2. B. 0

      Would be the value read if the static field were legal, but the mutable static declaration prevents compilation.

    3. C. An exception is thrown at runtime

      The problem is caught at compile time, so no program runs to throw.

    4. D. It compiles; local classes may have static fields

      Local classes may hold only static final constants, not a mutable static field, so this general claim is false.

    Explanation

    In Java 8, local and inner classes may not declare static members except compile-time CONSTANTS (static final with a constant initializer). A mutable static int is rejected: "static declarations not allowed". (`static final int counter = 0;` would compile.)

  3. Question 3

    The Box class is intended to be immutable. What is the output of the following program? ```java import java.util.ArrayList; import java.util.List; public class Main { static final class Box { private final List<String> items; Box(List<String> items) { this.items = new ArrayList<>(items); } List<String> items() { return items; } } public static void main(String[] args) { List<String> src = new ArrayList<>(); src.add("a"); Box b = new Box(src); src.add("ignored"); b.items().add("leaked"); System.out.println(b.items().size()); } } ```

    1. A. 3

      The constructor's defensive copy isolates the box from the later external add, so that change does not count and the size is not 3.

    2. B. An UnsupportedOperationException is thrown

      The accessor returns a plain mutable ArrayList, not an unmodifiable view, so adding to it succeeds rather than throwing.

    3. C. 2Correct answer

      The defensive copy blocks the external add, but the accessor returns the internal list directly, so the leaked add mutates the box's own state, giving size 2.

    4. D. 1

      This assumes the accessor also returns a copy, but it exposes the internal list directly, so the leaked add raises the size to 2.

    Explanation

    Copying the incoming list in the constructor isolates the object from later mutations of the caller's list, but returning the internal list directly from the accessor leaks that reference, letting outside code mutate the object's own state. True immutability requires defensive copies on the way out as well as in, or an unmodifiable wrapper.

  4. Question 4

    What is the output of the following program? ```java import java.util.HashSet; import java.util.Set; public class Main { static class Key { int id; Key(int id) { this.id = id; } public boolean equals(Object o) { return o instanceof Key && ((Key) o).id == id; } // hashCode intentionally NOT overridden } public static void main(String[] args) { Set<Key> set = new HashSet<>(); set.add(new Key(1)); set.add(new Key(1)); System.out.println(set.size()); } } ```

    1. A. 2Correct answer

      With the default identity hashCode the two equal keys hash to different buckets, equals is never consulted, and both are stored, so the size is 2.

    2. B. Compilation fails because hashCode must be overridden with equals

      Overriding equals without hashCode is legal to compile; the pairing is a runtime contract, not a compile-time requirement.

    3. C. An exception is thrown at runtime

      Nothing throws here; the set simply stores both elements.

    4. D. 1

      This assumes equals alone deduplicates, but the set consults hashCode first, and the mismatched identity hashes keep the two keys apart.

    Explanation

    A hash set locates candidates by hash code before it ever calls equals, so a class that overrides equals but keeps the default identity hash code scatters equal objects into different buckets, where equals is never consulted and both are stored. Breaking the equals/hashCode pairing compiles cleanly but silently breaks hash-based collections.

  5. Question 5

    What is the output of the following program? ```java public class Main { static class Point { int x; Point(int x) { this.x = x; } public boolean equals(Point p) { return p != null && p.x == x; } } public static void main(String[] args) { Object a = new Point(1); Object b = new Point(1); System.out.println(a.equals(b) + " " + new Point(1).equals(new Point(1))); } } ```

    1. A. Compilation fails

      Declaring equals(Point) is a legal overload alongside the inherited equals(Object), so the code compiles cleanly.

    2. B. false trueCorrect answer

      Through Object references the inherited identity equals(Object) runs and returns false; through Point references the overload equals(Point) is chosen at compile time and returns true.

    3. C. false false

      This assumes the identity equals runs in both cases, but the Point-typed call resolves to the content-comparing overload at compile time and returns true.

    4. D. true true

      This assumes equals(Point) overrides Object.equals and runs for the Object-typed call too, but it is only an overload; through Object references the inherited identity equals runs and returns false.

    Explanation

    equals(Point) does NOT override Object.equals(Object) — it's an unrelated OVERLOAD. Through Object references the inherited identity equals runs (false); through Point references the overload is chosen at compile time (true). The correct override must take an Object parameter — the classic signature trap.

  6. Question 6

    What is the output of the following program? ```java public class Main { interface Greeting { String speak(); } public static void main(String[] args) { Greeting g = new Greeting() { public String speak() { return "anon"; } }; System.out.println(g.speak()); } } ```

    1. A. Compilation fails because an interface cannot be instantiated

      This is not instantiating the interface; the new Interface() { ... } form declares and instantiates an anonymous implementing class, which is legal.

    2. B. anonCorrect answer

      The inline speak() body runs and returns the literal "anon".

    3. C. Compilation fails because the class has no name

      An anonymous class is intentionally nameless, which is permitted, so lacking a name is not an error.

    4. D. null

      The supplied speak() body returns the literal, so the output is that string, not null.

    Explanation

    The new Interface() { ... } form does not instantiate the interface itself; it declares an anonymous class that implements the interface and instantiates it in a single expression, which is legal even though the class is nameless. The inline method body runs and returns its literal.

  7. Question 7

    What is the output of the following program? ```java public class Main { int v = 1; class In { int v = 2; int both() { return v + Main.this.v; } } public static void main(String[] args) { System.out.println(new Main().new In().both()); } } ```

    1. A. Compilation fails because Main.this is invalid syntax

      Outer.this is valid syntax precisely for reaching an enclosing instance's members, so it compiles.

    2. B. 3Correct answer

      Correct: the inner field is 2 and the outer field via the qualified this is 1, summing to this value.

    3. C. 2

      This counts only the inner field, ignoring the qualified reference to the outer one.

    4. D. 4

      This would require both fields to hold 2, but the outer field is 1.

    Explanation

    A shadowed field name inside an inner class refers to the inner field, while the qualified Outer.this form reaches the enclosing instance's field of the same name. Adding the two distinct values gives the result.

  8. Question 8

    What is the output of the following program? ```java public class Main { enum Planet { MERCURY(0), EARTH(3); private final int order; Planet(int order) { this.order = order; System.out.print("c"); } int order() { return order; } } public static void main(String[] args) { System.out.print(Planet.EARTH.order()); System.out.println(Planet.MERCURY.order()); } } ```

    1. A. c3c0

      This assumes the constructor runs lazily on each access, interleaving its print with the order values; in fact all constants are built together when the enum is first used.

    2. B. Compilation fails because enum constructors cannot take arguments

      Enum constructors may take arguments, which is exactly how per-constant state is set, so this compiles.

    3. C. 30

      This overlooks the two constructor prints; the constructor runs once per constant, emitting "cc" before any order value.

    4. D. cc30Correct answer

      Both constants are constructed first (printing "cc"), then EARTH.order() yields 3 and MERCURY.order() yields 0, giving "cc30".

    Explanation

    Enum constants are all constructed once, together, when the enum type is first initialized, so every constructor side effect happens before any constant is used. Enum constructors routinely take arguments to set per-constant state. Both constructions print first, then the two order values follow.

Practise all 25 Advanced Class Design & Design Patterns questions

OCP Java SE 8 has the full set, inside timed mock exams that mirror real exam conditions — every question with a worked explanation.

Open OCP Java SE 8

Other topics in this pack