java-encapsulamiento-modificadores-acceso

Encapsulamiento en Java: private, public y getters

  • 3 min

El encapsulamiento consiste en limitar el acceso al estado interno de un objeto y exponer operaciones controladas.

En el artículo anterior dejamos nuestros objetos Robot con sus atributos expuestos. Cualquier parte del programa podía hacer esto:

miRobot.nivelBateria = -5000; // ¡Destrozando la lógica!
miRobot.nombre = null;        // Rompiendo el sistema
Copied!

Si permitimos el acceso directo a los datos, perdemos el control. No podemos validar si los datos son correctos.

Este problema nos lleva al segundo pilar de la programación orientada a objetos: el encapsulamiento.

El encapsulamiento consiste en ocultar los detalles internos de una clase y exponer solo lo que sea seguro y necesario.

Los modificadores de acceso

Java nos da cuatro niveles de seguridad para decidir “quién puede ver qué”. Se aplican a clases, atributos y métodos.

ModificadorMisma ClaseMismo PaqueteSubclase (otro paquete)Mundo (Todo)
public
protected
Default
private

Es el nivel más permisivo. Cualquiera, desde cualquier parte del proyecto, puede acceder.

  • Uso: Métodos que forman parte de la API pública (lo que quieres que usen los demás).

Es el nivel más restrictivo. Solo la propia clase puede ver esos datos. Ni siquiera las clases vecinas.

  • Uso: TODOS los atributos deberían ser privados por defecto.

Es un nivel intermedio. Permite el acceso a:

  1. La propia clase.
  2. Las clases del mismo paquete.
  3. Las subclases (hijas), aunque estén en otro paquete.
  • Uso: Lo veremos a fondo cuando lleguemos a la Herencia.

Si no escribes nada (ni public, ni private…), Java aplica este nivel por defecto. Permite el acceso a cualquier clase dentro del mismo paquete.

  • Uso: Clases de utilidad internas que solo sirven para ayudar a otras clases del módulo.

Getters y setters: los porteros de discoteca

Si ponemos todos los atributos private (como debe ser), nadie podrá leer ni cambiar el nombre de nuestro Robot. El objeto sería una caja negra inútil.

Para permitir el acceso controlado, creamos métodos públicos especiales: los Getters (para leer) y los Setters (para escribir).

¿Por qué hacer esto y no dejarlo público?

La ventaja de un setter es que permite ejecutar validaciones antes de guardar el dato.

public class Robot {
    // 1. ATRIBUTO PRIVADO (Blindado)
    private int nivelBateria;

    // 2. GETTER (Lectura)
    public int getNivelBateria() {
        return this.nivelBateria;
    }

    // 3. SETTER (Escritura controlada)
    public void setNivelBateria(int nuevoNivel) {
        // VALIDACIÓN: Evitamos valores absurdos
        if (nuevoNivel < 0) {
            System.out.println("Error: La batería no puede ser negativa. Se pone a 0.");
            this.nivelBateria = 0;
        } else if (nuevoNivel > 100) {
            this.nivelBateria = 100;
        } else {
            this.nivelBateria = nuevoNivel;
        }
    }
}
Copied!

Ahora, desde fuera:

Robot r = new Robot();
// r.nivelBateria = -50; // ERROR: No compila, es privado.

r.setNivelBateria(-50); // El setter intercepta el error y lo corrige a 0.
System.out.println(r.getNivelBateria()); // Leemos de forma segura.
Copied!

Objetos de solo lectura (inmutabilidad)

Si quieres que un atributo sea de lectura pero no se pueda modificar una vez creado, simplemente no crees el Setter.

public class DNI {
    private String numero;

    public DNI(String n) {
        this.numero = n;
    }

    // Solo Getter. Nadie podrá cambiar el número del DNI después de nacer.
    public String getNumero() {
        return numero;
    }
}
Copied!