Lezioni del modulo (1/2)
Interfacce
Mentre le classi astratte possono contenere sia codice parzialmente implementato che campi istanza, le interfacce in Java sono contratti di puro comportamento. Un'interfaccia definisce cosa una classe deve saper fare, ma non come lo fa.
Questo consente un disaccoppiamento totale tra la definizione delle operazioni e la loro implementazione reale.
Definire un'Interfaccia (interface)
Si usa la parola chiave interface. Tutti i metodi dichiarati in un'interfaccia sono implicitamente public e abstract (non è necessario specificarlo):
interface Drivable {
void startEngine();
void stopEngine();
}
Implementare un'Interfaccia (implements)
Una classe implementa un'interfaccia usando la parola chiave implements ed è obbligata a fornire l'implementazione (con il corpo) per tutti i metodi definiti:
class Motorcycle implements Drivable {
@Override
public void startEngine() {
System.out.println("Rombo del motore acceso!");
}
@Override
public void stopEngine() {
System.out.println("Motore spento.");
}
}
Vantaggi delle Interfacce
- Ereditarietà Multipla: In Java, una classe può estendere una sola classe padre (ereditarietà singola), ma può implementare molteplici interfacce contemporaneamente.
Code
class HybridCar implements Drivable, Chargeable { ... } - Disaccoppiamento: Puoi definire variabili usando il tipo dell'interfaccia. Qualsiasi oggetto che implementa quell'interfaccia può essere assegnato a tale variabile.
Code
Drivable vehicle = new Motorcycle(); vehicle.startEngine();
Costanti nelle Interfacce
Nelle interfacce è possibile dichiarare dei campi. Questi campi sono implicitamente public static final (ossia costanti di classe), anche se non si specificano questi modificatori. Di conseguenza, devono essere inizializzati immediatamente al momento della dichiarazione:
interface PhysicsConstants {
double GRAVITY = 9.81; // Implicitamente public static final
}
Metodi di Default (default)
A partire da Java 8, è possibile definire metodi con un'implementazione di default all'interno di un'interfaccia usando la parola chiave default. Questi metodi non obbligano le classi che implementano l'interfaccia a sovrascriverli, fornendo un comportamento di ripiego:
interface Logger {
void log(String message);
// Metodo di default con corpo
default void logError(String message) {
log("ERRORE: " + message);
}
}
Prova tu
Crea l'interfaccia Flyable con il metodo void fly(). Successivamente implementa la classe Bird in modo che implementi Flyable e stampi Flying a schermo.
Mostra suggerimento
In Flyable scrivi `void fly();`. Nella classe Bird implementa il metodo marcandolo con `@Override public void fly() { System.out.println('Flying'); }`.
Soluzione disponibile dopo 3 tentativi
Definisci l'interfaccia Drawable con il metodo void draw(). Poi implementa la classe Rectangle in modo che implementi Drawable e stampi Drawing Rectangle.
Mostra suggerimento
Definisci `void draw();` nell'interfaccia. In Rectangle usa `@Override public void draw() { System.out.println('Drawing Rectangle'); }`.
Soluzione disponibile dopo 3 tentativi
Completa l'interfaccia Swimmable definendo il metodo void swim(). Successivamente, completa la classe Duck in modo che implementi sia Flyable che Swimmable, stampando Flying nel metodo fly() e Swimming nel metodo swim().
Mostra suggerimento
Dichiara `void swim();` in Swimmable. Dichiara `class Duck implements Flyable, Swimmable` e implementa entrambi i metodi stampando le stringhe richieste.
Soluzione disponibile dopo 3 tentativi