March 1, 2021 | Download a PDF of this article
More quiz questions available here
If you have worked on our quiz questions in the past, you know none of them is easy. They model the difficult questions from certification examinations. We write questions for the certification exams, and we intend that the same rules apply: Take words at their face value and trust that the questions are not intended to deceive you but to straightforwardly test your knowledge of the ins and outs of the language.
Given the following classes and an interface:
interface Flyable {
public default void fly() {
System.out.print("Default fly");
};
}
abstract class Bird implements Flyable {
public abstract void fly();
}
class Chicken extends Bird implements Flyable {
public void fly() {
System.out.print("Cannot fly");
};
}
class BirdsFarm {
public static void main(String[] args) {
Bird b = new Chicken();
Flyable f = b;
f.fly();
}
}
What is the result? Choose one.
Answer. The code in this question sets out three types in a hierarchy: the interface Flyable
, the abstract class Bird
, and the concrete class Chicken
. The interface Flyable
provides a default method fly()
.
The Bird
class is perhaps a little surprising. First, it hides the default fly
method, replacing it with an abstract method of the same signature. This is where the surprise might be: The default method is now inaccessible, and any subclasses must explicitly provide a new implementation of fly
. Although it might be surprising, it is valid in Java, and the code compiles. Therefore, option A is incorrect. It might also be surprising that subclasses cannot use the super
keyword to get at the default fly
method defined in Flyable
.
Next, notice that the Chicken
class implements the fly
method. As just described, it is actually mandatory for the Chicken
to implement fly
if Chicken
is to be a concrete class. The syntax is valid and the code compiles successfully. So, the Chicken
class is valid, the code compiles successfully, and option B is incorrect.
There are a couple of additional things to note for this part of the discussion. First, even if the Bird
class did not hide the Flyable.fly
method, thereby preventing access to it from the Chicken
class, that would not be a problem. Why? Because you should expect overriding methods to replace parent methods whether they’re concrete methods in classes or the default methods in an interface. Although it’s redundant, explicitly stating that the Chicken
class implements Flyable
is legal syntax. (However, it does not in any way reveal the hidden fly
method in the Flyable
interface.)
The second thing to note is that if a class implements two interfaces that have default methods with the same signatures, and neither that class nor the classes it extends explicitly implement those methods, then having two default methods does create a conflict. In such a case, the compiler refuses to make a judgment about which of the two default methods should be used, and compilation fails.
By the way, this is a form of the diamond inheritance problem. (See Michael Kölling’s article, “The evolving nature of Java interfaces,” and also another one of our quizzes.)
However, if there is a concrete implementation of the default methods anywhere in the class hierarchy (and here we’re being specific about classes as opposed to interfaces), then that method resolves the conflict. Such a method can usually use a variant of the super
syntax to invoke a selected default method from an interface. In a typical case, that syntax might look like Flyable.super.fly()
except that, as has been noted, in this particular example, the abstract version of fly
completely hides the default one.
We’ve now established that the code compiles. When it runs, the normal rules apply to the selection of the fly
method that will be executed. This decision about which to execute is made according to the type of the object (which is a Chicken
), not according to the type of the reference (which is Flyable
). This is the normal late or virtual binding behavior for nonprivate instance methods in Java. As a result, the output will be Cannot fly
, which makes option D correct and option C incorrect.
By the way, Simon’s three chickens, Dutchess, Sheila, and Buffy, would like you to know that they are offended by this question, asserting strenuously that they can fly, albeit not very well.
Conclusion: The correct answer is option D.