6.2. Use interfaces

[7.1] Describe inheritance and its benefits

[7.5] Use abstract classes and interfaces

We all use interfaces quite often in our lives. For example, when you refer to someone as a runner, do you care whether that person is also an orator, a parent, or an entrepreneur? You care only that the person is able to run. The term runner enables you to refer to unrelated individuals, by opening a small window to each person and accessing behavior that’s applicable to only that person’s capacity as a runner. Someone can be referred to as a runner only if that person supports characteristics relevant to running, though the specific behavior can depend on the person.

In the preceding example, you can compare the term runner to a Java interface, which defines the required behavior run. An interface can define a set of behaviors (methods) and constants. Usually it delegates the implementation of the behavior to the classes that implement it. Interfaces are used to refer to multiple related or unrelated objects that share the same set of behaviors. Figure 6.7 compares the interface runner with a small window to an object, which is concerned only about the running capabilities of that object.

Figure 6.7. You can compare an interface with a window that can connect multiple objects but has limited access to them.

Similarly, when you design your application by using interfaces, you can use similar windows (also referred to as specifications or contracts) to specify the behavior that you need from an object, without caring about the specific types of objects.

Note

You can compare a contract with a set of rules or deliverables that are mutually accepted by persons. A contract might include a set of rules to abide by or deliverables to be made accessible by a certain date. A contract usually doesn’t include how the rules stated would be abided by or how the deliverables would be made accessible. It states what and not how. Similarly, an interface defines what behavior would be supported by the classes that implement it.

Separating the required behavior from its implementation has many benefits. As an application designer, you can use interfaces to establish the behavior that’s required from objects, promoting flexibility in the design (new classes that implement an interface can be created and used later). Interfaces make an application manageable, extensible, and less prone to propagation of errors due to changes to existing types.

Now imagine you created an interface in an application some time ago. The application needs to be upgraded, which requires additional behavior to be added to some of its interfaces. This wouldn’t have been possible with Java 7 or its earlier versions. But with Java 8, you can add methods to an interface without breaking the existing implementations. Prior to Java 8, an interface could only define abstract methods. With Java 8, an interface can define the default implementation for its methods (so it doesn’t stop the existing classes that implement it from compiling). Interfaces in Java 8 can also define static methods. One of the main reasons for this language change (adding default and static methods to interfaces) was to improve the aging Collections API, especially with Stream-based functionalities (covered by the OCP exam).

In this section, you’ll come to understand the need for and importance of using interfaces and different types of methods that can be defined in an interface. You’ll work with the implicit and explicit properties of interface members—its constants and methods. You’ll also see why inheriting multiples classes isn’t allowed but inheriting multiple interfaces is allowed. Let’s get started with the need for interfaces.

6.2.1. Need for using interfaces

You need interfaces to enable multiple classes to support a set of behaviors. Let’s work with the example used in section 6.1. In this example, Employee is the base class and classes Programmer and Manager subclass Employee. Imagine that your boss steps in and states that Programmer and Manager must support additional behaviors, as listed in table 6.1.

Table 6.1. Additional behaviors that need to be supported by the classes Programmer and Manager

Entity

New expected behavior

Programmer Attend training
Manager Attend training, conduct interviews

How will you accomplish this task? One approach you can take is to define all the relevant methods in the class Employee. Because both Programmer and Manager extend the class Employee, they’d be able to access these methods. But wait: Programmer doesn’t need the behavior of the conducting interview task; only Manager should support the functionality of conducting interviews.

Another obvious approach would be to define the relevant methods in the desired classes. You could define methods to conduct interviews in Manager and methods to attend training in both Programmer and Manager. Again, this isn’t an ideal solution. What will happen if your boss later informs you that all the Employees who attend training should accept a training schedule; that is, there’s a change in the signature of the method that defines the behavior “attend training”? Can you define separate classes for this behavior and make the classes Programmer and Manager implement them? No, you can’t. Java doesn’t allow a class to inherit multiple classes (covered in a later section in this chapter).

Let’s try interfaces. Create two interfaces to define the specified behavior:

interface Trainable {
    public void attendTraining();
}

interface Interviewer {
    public void conductInterview();
}

Although Java doesn’t allow a class to inherit from more than one class, it allows a class to implement multiple interfaces. A class uses the keyword implements to implement an interface. In the following code, the classes Programmer and Manager implement the relevant interfaces (the modified code is in bold):

Figure 6.8 displays the relationships between these classes in a UML diagram.

Figure 6.8. Relationships among the classes Employee, Programmer, and Manager and the interfaces Trainable and Interviewer

Note

An interface can be represented in UML diagrams using either a rectangle with the text <<interface>> or simply a circle. Both notations are popular; you may see them in various websites or books.

The preceding relationships can also be represented as depicted in figure 6.9, where the interfaces are defined as circles.

Figure 6.9. Relationships among the classes Employee, Programmer, and Manager and the interfaces Trainable and Interviewer, with interfaces represented by circles

6.2.2. Defining interfaces

You can define methods and constants in an interface. Declaring an interface is simple, but don’t let this simplicity take you for a ride. For the exam, it’s important to understand the implicit modifiers that are added to the members of an interface. All methods of an interface are implicitly public. The interface variables are implicitly public, static, and final. Let’s define an interface Runner that defines an abstract method speed and a variable distance. Figure 6.10 shows how implicit modifiers are added to the members of interface Runner during the compilation process.

Figure 6.10. All the methods of an interface are implicitly public. Its variables are implicitly public, static, and final.

Why do you think these implicit modifiers are added to the interface members? Because an interface is used to define a contract, it doesn’t make sense to limit access to its members—and so they are implicitly public. An interface can’t be instantiated, and so the value of its variables should be defined and accessible in a static context, which makes them implicitly static.

The exam will also test you on the various components of an interface declaration, including access and nonaccess modifiers. Here’s the complete list of the components of an interface declaration:

  • Access modifiers
  • Nonaccess modifiers
  • Interface name
  • All extended interfaces, if the interface is extending any interfaces
  • Interface body (variables and methods), included within a pair of curly braces {}

To include all the possible components, let’s modify the declaration of the interface Runner:

public strictfp interface Runner extends Athlete, Walker {}

The components of the interface Runner are shown in figure 6.11. To declare any interface, you must include the keyword interface, the name of interface, and its body, marked by {}.

Figure 6.11. Components of an interface declaration

The optional and compulsory components of an interface can be summarized as listed in table 6.2.

Table 6.2. Optional and compulsory components of an interface declaration

Compulsory

Optional

Keyword interface Access modifier
Name of the interface Nonaccess modifier
Interface body, marked by the opening and closing curly braces {} Keyword extends, together with the name of the base interface(s) (Unlike a class, an interface can extend multiple interfaces.)
Exam Tip

The declaration of an interface can’t include a class name. An interface can never extend any class.

Can you define a top-level, protected interface? No, you can’t. For the exam, you must know the answer to questions about the correct values for each component that can be used with an interface declaration. Let’s dive into these nuances.

Valid access modifiers for an interface

You can declare a top-level interface (the one that isn’t declared within any other class or interface), with only the following access levels:

  • public
  • No modifier (default access)

If you try to declare your top-level interfaces by using the other access modifiers (protected or private), your interface will fail to compile. The following definitions of the interface MyInterface won’t compile:

Exam Tip

All the top-level Java types (classes, enums, and interfaces) can be declared using only two access levels: public and default. Inner or nested types can be declared using any access level.

Valid access modifiers for members of an interface

All members of an interface—variables, methods, inner interfaces, and inner classes (yes, an interface can define a class within it!)—are inherently public because that’s the only modifier they can accept. Using other access modifiers results in compilation errors:

The code at fails compilation with the following error message:

illegal combination of modifiers: public and private
    private int number = 10;
Valid nonaccess modifiers for an interface

You can declare a top-level interface with only the following nonaccess modifiers:

  • abstract
  • strictfp
Note

The strictfp keyword guarantees that results of all floating-point calculations are identical on all platforms.

If you try to declare your top-level interfaces by using the other nonaccess modifiers (final, static, transient, synchronized, or volatile), the interface will fail to compile. All the following interface declarations fail to compile because they use invalid nonaccess modifiers:

6.2.3. Types of methods in an interface

Oracle has made fundamental changes to interfaces in Java 8. Apart from abstract methods, an interface can define methods with default implementations. It can also define static methods. Here’s a quick list of the types of methods that can be defined in an interface (in Java 8):

  • abstract methods
  • Default methods (new in Java 8)
  • static methods (new in Java 8)

Let’s examine each of these in detail.

Note

The default methods are also referred to as defender or virtual extension methods. But the most popular term to refer them is default methods because the default keyword is used to identify them.

abstract methods

Most jobs require a candidate to be interviewed, and the interviewer can be a CEO, a technical leader, or a programmer. Although each of these categories supports the behavior of an interviewer, it will conductInterview in its own specific manner.

An abstract method is used to specify a behavior (set of methods), which must be defined by the class that implements it. It’s another way of stating “a class supports a behavior, but in its own manner” in the way it likes. In the following example, the interface Interviewer defines an abstract method conductInterview.

An abstract method is defined without a method body:

You might include the keyword abstract to define an abstract method in an interface. The following definition of the method conductInterview is the same as its definition in the preceding code:

Exam Tip

Interface methods are implicitly abstract. To define default or static methods, you must explicitly use the keyword default or static with the method declaration in an interface. Default and static methods include their implementation in an interface.

When a class implements an interface with abstract methods, the class must implement all the methods, or else the class won’t compile. A developer can’t add abstract methods to an interface without breaking existing implementations. It can only be done with default methods.

Default methods

Imagine you need to add a behavior—submit interview status—to the interface Interviewer, after its publication. This wouldn’t have been possible with Java 7 and its earlier versions without implying the need to provide an implementation for each existing concrete class (either directly or through a superclass). Default methods can rescue you here. Starting with Java 8, interfaces can be augmented by adding methods with default implementation. Implementing classes might choose to override these methods to define their own specific behavior. If they don’t choose to override them, the default implementation from the interface is used. The definition of a default method must include the keyword default:

I deliberately oversimplified submitInterviewStatus() in the preceding code so that the code focuses on the definition of default methods and not on its implementation details.

New in Java 8

Interface methods can define an implementation by using default methods.

Because the return type of the preceding method, submitInterviewStatus, is void, the following definition of method submitInterviewStatus is valid:

Even though the method in the preceding example doesn’t define any code in its body, it isn’t equivalent to an abstract method. Declaration of a default method must be followed by the method body marked using {}. The following code won’t compile:

Just like regular methods, the return type of a default method must match the type of the value that it returns. The following won’t compile:

static methods

Revisit the interface Interviewer used in the preceding section. Imagine that you need a utility (static) method that can be used to book a conference hall for an interview on a particular date and time. With Java 8, you can add static methods to an interface. Prior to Java 8, interfaces weren’t allowed to define static methods. In such a case, you’d need to define the required static method in a separate class. This is one of the main reasons why static methods have been allowed in the interfaces—to improve the aging Collections API, which includes a few classes just to define static methods (like Collections and Paths).

Note

static interface methods enable you to define utility methods in the interfaces that they belong to.

Let’s add a static method bookConferenceRoom to the interface Interviewer (in bold):

interface Interviewer {
    abstract void conductInterview();
    default void submitInterviewStatus() {
        System.out.println("Accept");
    }
    static void bookConferenceRoom(LocalDateTime dateTime, int duration) {
        System.out.println("Interview scheduled on:" + dateTime);
        System.out.println("Book conference room for: "+duration + " hrs");
    }
}

The method bookConferenceRoom() must be called by prefixing its call with the interface name. You can’t call it using a reference variable of the type Interviewer or of the class that implements this interface. Let’s define the class Manager that implements Interviewer and the class Project that tries to call the method bookConferenceRoom:

It’s interesting to note that for mgr.bookConferenceRoom(), the compiler states that the method bookConferenceRoom is not defined for the type Manager.

Exam Tip

A static method in an interface can’t be called using a reference variable. It must be called using the interface name.

In contrast to the preceding code, you can call a static method defined in a class either by using reference variables or by the name of the class:

In the preceding example, the static method defaultPlan is defined in the class Employee, which is subclassed by the class Programmer. The class Project defines reference variables of the type Employee and Programmer and initializes them using Programmer instances. To execute defaultPlan(), you can use the reference variables emp and pgr of types Employee and Programmer, respectively. You can also call default-Plan() by using the class name: Employee or Programmer.

Exam Tip

Unlike an interface, if you define a static method in a base class, it can be accessed using either a reference variable or the class name.

6.2.4. Implementing a single interface

When a class implements an interface, it must follow a set of rules.

Implement abstract methods

If a concrete class doesn’t implement the abstract methods of the interface it implements, it won’t compile:

Do you think the following code will compile?

Exam Tip

You must implement an abstract method of an interface using the explicit access modifier public.

When you implement an interface method in a class, it follows method-overriding rules:

But the following won’t compile:

Overriding default methods

A class might choose to override the implementation of a default method in an interface that it implements. If it doesn’t, the default implementation of the interface method will be used. In the following example, the class Manager implements the interface Interviewer but doesn’t override the default method submitInterview-Status():

Let’s override the default implementation of the method submitInterviewStatus() in the class Manager. When a class overrides a default method, it doesn’t use the keyword default. Also, it follows method-overriding rules:

Exam Tip

While overriding a default method, you must not use the keyword default. Rules for overriding default and regular methods are the same.

static methods

If an interface defines a static method, the class that implements it can define a static method with the same name, but the method in the interface isn’t related to the method defined in the class. In the following example, the method bookConference-Room in the class Manager doesn’t overload or override the method bookConference-Room defined in the interface Interviewer. This is evident from the return types of these methods (highlighted in bold):

Exam Tip

static methods in a class and the interface that it implements are not related to each other. A static method in a class doesn’t hide or override the static method in the interface that it implements.

Why do you think Java doesn’t allow a class to inherit multiple classes but allows a class to implement multiple interfaces? I’ll cover that in detail in the next sections.

6.2.5. A class can’t extend multiple classes

In Java, a class can’t extend multiple classes. Let’s examine the reason using an example, in which the class Programmer is allowed to inherit two classes: Employee and Philanthropist. Figure 6.12 shows the relationship between these classes and the corresponding code.

Figure 6.12. What happens if a class is allowed to extend multiple classes?

If the class Programmer inherited the method receiveSalary, defined in both Employee and Philanthropist, what do you think a Programmer would do with their salary: pay dues (like an Employee) or donate it (like a Philanthropist)? What do you think would be the output of the following code?

In this case, the class Programmer can access two receiveSalary methods with identical method signatures but different implementations, so it’s impossible to resolve this method call. This is why classes aren’t allowed to inherit multiple classes in Java.

Exam Tip

Because a derived class may inherit different implementations for the same method signature from multiple base classes, multiple inheritance isn’t allowed in Java.

6.2.6. A class can implement multiple interfaces

In the preceding section, we discussed that a class can’t inherit multiple classes. But a class can implement multiple interfaces. Why is this allowed, when Java doesn’t allow a class to extend multiple classes? Prior to Java 8, an interface could define only abstract methods. So even if a class inherited methods with the same name from different interfaces, it came without an implementation.

But with Java 8, an interface can also define default methods—methods that include an implementation. So when a class implements multiple interfaces, it must adhere to a set of rules.

Exam Tip

A class can extend multiple interfaces only if a set of rules is adhered to.

Implementing multiple interfaces with the same constant names

A class can implement multiple interfaces with the same constant name, as long as a call to these interfaces isn’t ambiguous. In the following example, the class Animal compiles successfully. It doesn’t use the constant MIN_DISTANCE defined in the interfaces Moveable and Jumpable that it implements:

If you modify the implementation details of the class Animal so that it refers to the variable MIN_DISTANCE without prefixing it with the interface name, then it won’t compile:

When prefixed with the interface name, the reference to MIN_DISTANCE is no longer ambiguous:

If an implicit reference to a constant defined in an interface(s) isn’t ambiguous, the class that implements the interface can refer to it without prefixing it with the interface name:

Exam Tip

A class can implement multiple interfaces with the same constant names, only if a reference to the constants isn’t ambiguous.

Implementing multiple interfaces with the same abstract method names

An abstract method doesn’t define a body. It’s acceptable for a class to extend multiple interfaces that define abstract methods with the same signature because when a class implements the abstract method, it seems to implement the abstract method from all the interfaces:

interface Jumpable {
    abstract String currentPosition();
}
interface Moveable {
    abstract String currentPosition();
}
class Animal implements Jumpable, Moveable {
    public String currentPosition() {
        return "Home";
    }
}

But you can’t make a class extend multiple interfaces that define methods with the same name that don’t seem to be a correct combination of overloaded methods. If you change the return type of the method currentPosition() from String to void in the interface Moveable, the class Animal won’t compile. It would need to implement methods currentPosition, which differ only in their return type, which isn’t acceptable:

Exam Tip

A class can implement multiple interfaces with the same abstract method names if they have the same signature or form an overloaded set of methods.

Implementing multiple interfaces with the same default method names

Imagine a class, Animal, that extends multiple interfaces, Moveable and Jumpable, which define default methods with the same name, relax(). If the class Animal doesn’t override the default implementation of relax(), it won’t compile:

Let’s modify the preceding code, so that the class Animal overrides the default implementation of relax(). In this case, it will compile successfully:

The default methods that a class inherits from the interfaces that it implements must form a correct set of overloaded methods, or else the class won’t compile:

Exam Tip

A class can implement multiple interfaces with the same default method name and signature, if it overrides its default implementation.

Implementing multiple interfaces with the same static method names

A class can implement multiple interfaces that define static methods with the same name, even if they don’t qualify as correctly overloaded or overridden methods. This is because they’re not inherited by the class that implements the interfaces:

Exam Tip

A class can implement multiple interfaces with the same static method names, irrelevant of their return types or signature.

6.2.7. Extending interfaces

An interface can extend multiple interfaces. When an interface extends another interface, it must follow a set of rules.

Extending multiple interfaces with the same abstract method names

An abstract method doesn’t define a body. Consider the following code, whose UML representation is shown in figure 6.13. Which of the getName methods will be inherited by the interface MyInterface? Will MyInterface inherit the getName method defined in BaseInterface1 or the one defined in BaseInterface2?

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.82.154