Saltearse al contenido

Interfaces en Java

Una interfaz en Java es un tipo especial de clase que define un conjunto de métodos abstractos y constantes. A diferencia de una clase regular, una interfaz no puede ser instanciada directamente, sino que debe ser implementada por otra clase.

Las interfaces se utilizan para establecer contratos que las clases implementadoras deben cumplir. Esto promueve la modularidad, la reutilización de código y el polimorfismo.

Ejemplo 1: Definición e implementación de una interfaz

Supongamos que queremos definir un comportamiento común para diferentes tipos de vehículos. Podemos crear una interfaz llamada Vehiculo:

1
public interface Vehiculo {
2
void avanzar();
3
void frenar();
4
void cambiarVelocidad(int velocidad);
5
}

Ahora, podemos crear clases que implementen esta interfaz:

1
public class Automovil implements Vehiculo {
2
@Override
3
public void avanzar() {
4
System.out.println("El automóvil avanza");
5
}
6
7
@Override
8
public void frenar() {
9
System.out.println("El automóvil frena");
10
}
11
12
@Override
13
public void cambiarVelocidad(int velocidad) {
14
System.out.println("El automóvil cambia su velocidad a " + velocidad + " km/h");
15
}
16
}
17
18
public class Bicicleta implements Vehiculo {
19
@Override
20
public void avanzar() {
21
System.out.println("La bicicleta avanza");
22
}
23
24
@Override
25
public void frenar() {
26
System.out.println("La bicicleta frena");
27
}
28
29
@Override
30
public void cambiarVelocidad(int velocidad) {
31
System.out.println("La bicicleta cambia su velocidad a " + velocidad + " km/h");
32
}
33
}

Tanto Automovil como Bicicleta implementan la interfaz Vehiculo, por lo que deben proporcionar una implementación para todos los métodos definidos en la interfaz.

Ejemplo 2: Polimorfismo con interfaces

Una de las principales ventajas de las interfaces es que permiten el polimorfismo. Esto significa que podemos tratar objetos de diferentes clases como si fueran del mismo tipo, siempre que implementen la misma interfaz.

1
public class Main {
2
public static void moverVehiculo(Vehiculo vehiculo) {
3
vehiculo.avanzar();
4
vehiculo.cambiarVelocidad(60);
5
vehiculo.frenar();
6
}
7
8
public static void main(String[] args) {
9
Automovil auto = new Automovil();
10
Bicicleta bici = new Bicicleta();
11
12
moverVehiculo(auto); // Salida: El automóvil avanza, El automóvil cambia su velocidad a 60 km/h, El automóvil frena
13
moverVehiculo(bici); // Salida: La bicicleta avanza, La bicicleta cambia su velocidad a 60 km/h, La bicicleta frena
14
}
15
}

En este ejemplo, el método moverVehiculo acepta un objeto de tipo Vehiculo. Tanto Automovil como Bicicleta implementan la interfaz Vehiculo, por lo que podemos pasar instancias de estas clases al método moverVehiculo.

Ejemplo 3: Interfaces y clases abstractas

Las interfaces y las clases abstractas son complementarias en Java. Las interfaces definen un contrato que las clases implementadoras deben cumplir, mientras que las clases abstractas pueden proporcionar implementaciones parciales o predeterminadas de los métodos.

1
public abstract class VehiculoBase implements Vehiculo {
2
@Override
3
public void avanzar() {
4
System.out.println("El vehículo avanza");
5
}
6
7
@Override
8
public void frenar() {
9
System.out.println("El vehículo frena");
10
}
11
12
// Método abstracto que las subclases deben implementar
13
public abstract void cambiarVelocidad(int velocidad);
14
}
15
16
public class Automovil extends VehiculoBase {
17
@Override
18
public void cambiarVelocidad(int velocidad) {
19
System.out.println("El automóvil cambia su velocidad a " + velocidad + " km/h");
20
}
21
}

En este ejemplo, tenemos una clase abstracta VehiculoBase que implementa la interfaz Vehiculo. Esta clase proporciona implementaciones predeterminadas para los métodos avanzar() y frenar(), pero declara el método cambiarVelocidad(int velocidad) como abstracto.

La clase Automovil extiende de VehiculoBase y debe proporcionar una implementación para el método cambiarVelocidad(int velocidad).

Esta combinación de interfaces y clases abstractas permite una mayor flexibilidad y reutilización de código, al tiempo que proporciona implementaciones parciales o predeterminadas cuando sea necesario.