Module lessons (1/2)
Interfaces
While abstract classes can contain both partially implemented code and instance fields, interfaces in Java are contracts of pure behavior. An interface defines what a class must be able to do, but not how it does it.
This allows complete decoupling between the definition of operations and their actual implementation.
Defining an Interface (interface)
We use the interface keyword. All methods declared in an interface are implicitly public and abstract (no need to specify it):
interface Drivable {
void startEngine();
void stopEngine();
}
Implementing an Interface (implements)
A class implements an interface using the implements keyword and is required to provide the implementation (with a body) for all defined methods:
class Motorcycle implements Drivable {
@Override
public void startEngine() {
System.out.println("Rombo del motore acceso!");
}
@Override
public void stopEngine() {
System.out.println("Motore spento.");
}
}
Advantages of Interfaces
- Multiple Inheritance: In Java, a class can extend only one parent class (single inheritance), but it can implement multiple interfaces at the same time.
Code
class HybridCar implements Drivable, Chargeable { ... } - Decoupling: You can define variables using the interface type. Any object that implements that interface can be assigned to such a variable.
Code
Drivable vehicle = new Motorcycle(); vehicle.startEngine();
Constants in Interfaces
In interfaces, it is possible to declare fields. These fields are implicitly public static final (meaning class constants), even if you do not specify these modifiers. Consequently, they must be initialized immediately upon declaration:
interface PhysicsConstants {
double GRAVITY = 9.81; // Implicitly public static final
}
Default Methods (default)
Starting from Java 8, it is possible to define methods with a default implementation inside an interface using the default keyword. These methods do not force the implementing classes to override them, providing a fallback behavior:
interface Logger {
void log(String message);
// Default method with a body
default void logError(String message) {
log("ERROR: " + message);
}
}
Try it yourself
Create a Flyable interface with a void fly() method. Then implement a Bird class that implements Flyable and prints Flying to the screen.
Show hint
In Flyable, write `void fly();`. In the Bird class, implement the method marking it with `@Override public void fly() { System.out.println('Flying'); }`.
Solution available after 3 attempts
Define a Drawable interface with a void draw() method. Then implement a Rectangle class that implements Drawable and prints Drawing Rectangle.
Show hint
Define `void draw();` in the interface. In Rectangle, use `@Override public void draw() { System.out.println('Drawing Rectangle'); }`.
Solution available after 3 attempts
Complete the Swimmable interface by defining the void swim() method. Then, complete the Duck class so that it implements both Flyable and Swimmable, printing Flying in the fly() method and Swimming in the swim() method.
Show hint
Declare `void swim();` inside Swimmable. Declare `class Duck implements Flyable, Swimmable` and implement both methods printing the requested strings.
Solution available after 3 attempts