OCP Generics and Collections Questions and Answers 1 — Questions and Answers
Question 1: Which of the following statements is true regarding the behavior of generics in Java at runtime?
- Generic type information is discarded by the compiler through a process called type erasure. (Correct answer)
- The JVM maintains a separate class file for each specific instantiation of a generic type.
- Runtime reflection can be used to determine the exact parameterized type of a generic collection.
- A `List<String>` and a `List<Integer>` are treated as distinct types by the JVM, preventing runtime casting errors.
Correct answer: Generic type information is discarded by the compiler through a process called type erasure.
Java uses a process called type erasure to implement generics. During compilation, the generic type information is removed, and all generic types are replaced by their raw types (usually `Object` or an upper bound). This ensures backward compatibility with older Java versions that do not support generics. Consequently, at runtime, the JVM has no knowledge of the specific type parameters like `String` or `Integer` for a `List`, treating them all as a raw `List`.
Question 2: A developer needs to create a list of strings that will not be modified after its creation. Which of the following is the most appropriate way to initialize this list in modern Java (9 and later)?
- List<String> list = new ArrayList<>(); list.add("A"); list.add("B");
- List<String> list = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("A", "B")));
- List<String> list = List.of("A", "B"); (Correct answer)
- List<String> list = new LinkedList<>(List.of("A", "B"));
Correct answer: List<String> list = List.of("A", "B");
The `List.of()` factory method, introduced in Java 9, is the most concise and direct way to create an immutable list. The list it returns is unmodifiable, meaning any attempt to add, remove, or change elements will result in an `UnsupportedOperationException`. While `Collections.unmodifiableList` also creates an unmodifiable view, `List.of()` is preferred for its simplicity and efficiency for creating new, constant lists.
Question 3: What is the primary difference between the `Comparable` and `Comparator` interfaces in Java?
- `Comparator` is used for natural ordering, while `Comparable` is used for custom, external sorting logic.
- A class can implement multiple `Comparable` interfaces but only one `Comparator`.
- `Comparable` defines a single, natural ordering for a class, whereas `Comparator` allows for multiple, external sorting strategies. (Correct answer)
- The `compare()` method of `Comparator` takes one argument, while the `compareTo()` method of `Comparable` takes two.
Correct answer: `Comparable` defines a single, natural ordering for a class, whereas `Comparator` allows for multiple, external sorting strategies.
The `Comparable` interface is intended to be implemented by a class to define its 'natural ordering' via the `compareTo()` method. This provides a single, default way to sort objects of that class. The `Comparator` interface, on the other hand, is implemented in a separate class to define custom or multiple sorting strategies. This allows objects to be sorted in different ways without modifying their source code.
Question 4: Examine the following code snippet: ```java NavigableSet<Integer> set = new TreeSet<>(); set.add(10); set.add(20); set.add(30); set.add(40); System.out.println(set.lower(30)); System.out.println(set.floor(30)); System.out.println(set.higher(30)); ``` What will be the output?
- 20 30 40 (Correct answer)
- 20 20 40
- null 30 40
- 30 30 40
Correct answer: 20 30 40
The `NavigableSet` interface provides methods for finding elements relative to a given value. `lower(E e)` returns the greatest element strictly less than `e`. In this case, `set.lower(30)` returns 20. `floor(E e)` returns the greatest element less than or equal to `e`. So, `set.floor(30)` returns 30. `higher(E e)` returns the least element strictly greater than `e`, so `set.higher(30)` returns 40.
Question 5: Which generic wildcard should be used in a method signature `void process(List<?> list)` to allow the method to add `Integer` objects to the list?
- List<? extends Number>
- List<?>
- List<Object>
- List<? super Integer> (Correct answer)
Correct answer: List<? super Integer>
The `? super Integer` wildcard, known as a lower-bounded wildcard, restricts the unknown type to be a supertype of `Integer` (or `Integer` itself). This allows you to safely add `Integer` objects (or subtypes of `Integer`, though `Integer` is final) to the collection, as they will always be compatible with the list's actual type. An upper-bounded wildcard (`? extends T`) is for reading, and an unbounded wildcard (`?`) is also primarily for reading as the compiler cannot guarantee what type is safe to add.
Question 6: Which of the following is a key characteristic of the `java.util.Set` interface?
- It guarantees the order of elements based on insertion time.
- It allows for duplicate elements.
- It does not allow duplicate elements. (Correct answer)
- It provides index-based access to its elements via a `get(int index)` method.
Correct answer: It does not allow duplicate elements.
The fundamental contract of the `java.util.Set` interface is that it stores a collection of unique elements. It does not allow duplicate values. Attempting to add an element that is already present in the set will have no effect. Some implementations, like `LinkedHashSet`, may preserve insertion order, but this is not a guarantee of the `Set` interface itself. `Set` is not index-based and does not have a `get(int index)` method.
Which of the following statements is true regarding the behavior of generics in Java at runtime?