Interfaces y Clases Abstractas
## Objetivos de Aprendizaje
- Comprender las clases abstractas
- Crear e implementar interfaces
- Saber cuándo usar cada una
- Dominar los métodos default y static de interfaces
## Clases Abstractas
### No Pueden Ser Instantiadas
```java
public abstract class Shape {
String color;
public abstract double area(); // Método abstracto
public void display() { // Método concreto
System.out.println("Color: " + color);
}
}
```
### Subclase Concreta
```java
public class Circle extends Shape {
double radius;
public Circle(String color, double radius) {
this.color = color;
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
```
### Uso
```java
// Shape s = new Shape(); // Error - no se puede instanciar
Shape s = new Circle("Red", 5.0);
System.out.println(s.area()); // 78.54...
```
## Métodos Abstractos
### Sin Implementación
```java
public abstract class Animal {
public abstract void makeSound(); // Debe ser implementado
}
```
### Implementación Requerida
```java
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
```
## Interfaces
### Referencia: Contrato
```java
public interface Drawable {
void draw(); // Abstracto por defecto
}
```
### Implementación: Clases
```java
public class Circle implements Drawable {
@Override
public void draw() {
System.out.println("Drawing circle");
}
}
public class Rectangle implements Drawable {
@Override
public void draw() {
System.out.println("Drawing rectangle");
}
}
```
### Uso de Interface
```java
Drawable d = new Circle();
d.draw(); // Drawing circle
d = new Rectangle();
d.draw(); // Drawing rectangle
```
## Interface vs Clase Abstracta
| Característica | Clase Abstracta | Interface |
|----------------|-----------------|-----------|
| Campos | Cualquier tipo | Solo constantes |
| Métodos | Cualquiera | Default, static, abstract |
| Constructores | Sí | No |
| Herencia múltiple | No | Sí (múltiples interfaces) |
| Modificadores de acceso | Cualquiera | public (implícito) |
## Métodos Default (Java 8+)
### Proporcionar Implementación
```java
public interface Drawable {
void draw();
default void print() {
System.out.println("Printing...");
}
}
```
### Por qué Default?
Compatibilidad hacia atrás:
```java
public interface Drawable {
void draw();
// Nuevo método con implementación por defecto
default void print() {
System.out.println("Default print");
}
}
// Las clases existentes no se rompen - heredan default
```
## Métodos Estáticos en Interfaces
```java
public interface MathUtil {
static int add(int a, int b) {
return a + b;
}
static double circleArea(double radius) {
return Math.PI * radius * radius;
}
}
// Se llama como: MathUtil.add(5, 3)
```
## Múltiples Interfaces
### Clase Implementa Múltiples
```java
public interface Printable {
void print();
}
public interface Drawable {
void draw();
}
public class Document implements Printable, Drawable {
@Override
public void print() {
System.out.println("Printing document");
}
@Override
public void draw() {
System.out.println("Drawing document");
}
}
```
### Interface Extiende Interface
```java
public interface Readable extends Printable {
void read();
}
// La clase que implemente Readable debe implementar
// tanto read() (de Readable) como print() (de Printable)
```
## Campos de Interface
### Siempre Constantes
```java
public interface Constants {
int MAX_SIZE = 100; // public static final
String DEFAULT_NAME = "Unknown"; // public static final
}
// Uso
int size = Constants.MAX_SIZE;
```
## Interfaces Funcionales
### Método Abstracto Único
```java
@FunctionalInterface
public interface Comparator {
int compare(T o1, T o2);
// equals() ya está implementado (de Object)
}
```
### Expresiones Lambda
```java
import java.util.Arrays;
import java.util.Comparator;
String[] names = {"Charlie", "Alice", "Bob"};
Arrays.sort(names, (a, b) -> a.compareTo(b));
// o
Arrays.sort(names, Comparator.naturalOrder());
```
## Polimorfismo con Interfaces
```java
public interface Shape {
double area();
}
public class Circle implements Shape {
double radius;
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public class Rectangle implements Shape {
double width, height;
@Override
public double area() {
return width * height;
}
}
public static double totalArea(Shape[] shapes) {
double total = 0;
for (Shape s : shapes) {
total += s.area();
}
return total;
}
```
## Métodos Privados (Java 9+)
### Reutilización de Código en Interfaces
```java
public interface DataProcessor {
default void process(String data) {
String cleaned = clean(data);
validate(cleaned);
save(cleaned);
}
private String clean(String data) {
return data.trim().toLowerCase();
}
private void validate(String data) {
if (data.isEmpty()) {
throw new IllegalArgumentException("Empty data");
}
}
private void save(String data) {
// implementación de guardado
}
}
```
## Resumen
- Clases abstractas: implementación parcial, herencia simple
- Interfaces: solo contrato (históricamente), herencia múltiple
- `abstract class Shape` - usar cuando clases relacionadas comparten estado
- `interface Drawable` - usar cuando clases no relacionadas comparten comportamiento
- Los métodos default proporcionan compatibilidad hacia atrás
- Las interfaces soportan herencia múltiple
- Las interfaces funcionales pueden usar expresiones lambda
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →