</>waridocu

Java

Clases y objetos

Cómo definir una clase propia, crear objetos con new, constructores, this y encapsulación.

javaclasesobjetospooencapsulacion

El problema: datos que van juntos

Un ArrayList<String> con nombres y otro ArrayList<Integer> con notas, en paralelo, funcionan pero son frágiles: nada impide que se desordenen entre sí, y agregar un tercer dato (edad, legajo) significa un tercer array más para mantener sincronizado a mano. Lo que hace falta es un solo tipo que agrupe “nombre + nota” bajo un mismo nombre. Eso es exactamente lo que hace una clase.

Definir una clase propia

Hasta ahora Main fue la única clase de cada programa, y solo contenía main y algún método static. Una clase también puede describir un tipo de dato propio, con sus propios atributos:

Ejemplo: la clase Alumnojava
public class Alumno {
    String nombre;
    double nota;
}

nombre y nota son atributos (también llamados campos): cada Alumno que se cree va a tener su propia copia de estos dos valores. A diferencia de los métodos static de la página anterior, que pertenecían a la clase entera, un atributo sin static pertenece a cada objeto individual.

Crear objetos con new

class se traduce literalmente como “clase”, en el mismo sentido que “clase de animal” o “clasificar”: una categoría, un tipo de cosa. new se traduce como “nuevo”. Una clase es un molde para hacer galletitas; un objeto es cada galletita concreta que sale de ese molde, hecha con la palabra new (“haz una nueva”):

javajava
public class Main {
    public static void main(String[] args) {
        Alumno a1 = new Alumno();
        a1.nombre = "Ana";
        a1.nota = 8.5;

        Alumno a2 = new Alumno();
        a2.nombre = "Beto";
        a2.nota = 6.0;

        System.out.println(a1.nombre + ": " + a1.nota);
        System.out.println(a2.nombre + ": " + a2.nota);
    }
}
texttext
Ana: 8.5
Beto: 6.0

a1 y a2 son dos objetos distintos de la misma clase Alumno, cada uno con sus propios valores de nombre y nota — cambiar a1.nota no afecta a a2.nota para nada. Se accede a los atributos de un objeto con ., el mismo punto que ya usaste para teclado.nextLine() o notas.add(8)nextLine y add son métodos de objetos Scanner y ArrayList que ya venían hechos; ahora Alumno es un objeto hecho por ti.

Constructores

Asignar cada atributo a mano después de new Alumno() funciona, pero es fácil olvidarse de uno. Un constructor agrupa esa inicialización en un solo paso:

javajava
public class Alumno {
    String nombre;
    double nota;

    Alumno(String nombre, double nota) {
        this.nombre = nombre;
        this.nota = nota;
    }
}
javajava
Alumno a1 = new Alumno("Ana", 8.5);
Alumno a2 = new Alumno("Beto", 6.0);

El constructor se llama automáticamente cada vez que se usa new, y tiene el mismo nombre que la clase, sin tipo de retorno (ni siquiera void). Con un constructor así, es imposible crear un Alumno sin nombre o sin nota — el compilador exige los dos argumentos.

this: distinguir el atributo del parámetro

this se traduce literalmente como “esto” o “este” — en español sería algo como decir “el mío”, señalando al objeto propio en vez de a cualquier otro. En this.nombre = nombre;, hay dos cosas llamadas nombre: el parámetro del constructor y el atributo de la clase. this se refiere al objeto que se está construyendo en ese momento, así que this.nombre apunta sin ambigüedad al atributo, mientras que nombre a secas es el parámetro que acaba de llegar.

Nota

Nombrar el parámetro igual que el atributo (en vez de, por ejemplo, n o nombreNuevo) es una convención común precisamente porque this resuelve la ambigüedad — no hace falta inventar un nombre distinto solo para diferenciarlos.

Encapsulación: private y métodos de acceso

private se traduce literalmente como “privado” — lo mismo que en español: algo que no cualquiera puede tocar. Con nombre y nota declarados así, cualquier código puede hacer a1.nota = -50;, una nota que no tiene sentido, y la clase no puede evitarlo. La encapsulación es la práctica de ocultar los atributos y controlar cómo se leen y modifican, usando private y métodos dedicados:

javajava
public class Alumno {
    private String nombre;
    private double nota;

    Alumno(String nombre, double nota) {
        this.nombre = nombre;
        this.nota = nota;
    }

    double getNota() {
        return nota;
    }

    void setNota(double nuevaNota) {
        if (nuevaNota >= 0 && nuevaNota <= 10) {
            nota = nuevaNota;
        }
    }
}

private hace que nombre y nota solo sean accesibles desde dentro de la propia clasea1.nota desde main ya no compila. En su lugar, getNota() (un getter) permite leer el valor, y setNota(...) (un setter) permite modificarlo, pero solo si pasa la validación. Ahora a1.setNota(-50) simplemente no hace nada, en vez de dejar el objeto en un estado inválido.

Nota

Esta es la versión corta de la encapsulación, suficiente para seguir adelante. La página siguiente la desarrolla completa: los cuatro modificadores de acceso, la convención de nombres de los métodos y por qué el constructor también debería pasar por el setter.

Importante

No todos los atributos necesitan getter y setter — a veces alcanza con un getter (si el valor no debería cambiar después de creado) o ninguno de los dos (si el atributo es de uso puramente interno de la clase). La regla general es: haz private por defecto, y agrega acceso solo donde el resto del programa realmente lo necesita.

Pon a prueba

💡 Predice la salida

Con la clase Alumno de más arriba (con setNota validando el rango 0–10), ¿qué imprime este programa?

javajava
Alumno a = new Alumno("Caro", 7.0);
a.setNota(15);
System.out.println(a.getNota());
a.setNota(9);
System.out.println(a.getNota());

Imprime 7.0 y después 9.0. a.setNota(15) no cambia nada porque 15 está fuera del rango 0–10 que valida el if — la nota se queda en el valor que tenía desde el constructor. a.setNota(9) sí pasa la validación y actualiza el atributo. Este es exactamente el punto de la encapsulación: el objeto se protege solo de quedar en un estado que no tiene sentido.

🧩 Ordena el código

Ordena las líneas para definir una clase Punto con dos atributos y un constructor.

  1. private int y;
  2. this.x = x;
  3. Punto(int x, int y) {
  4. int getX() {
  5. return x;
  6. private int x;
  7. }
  8. public class Punto {
  9. }
  10. }
  11. this.y = y;

Siguiente paso

Con clases propias ya puedes modelar datos del mundo real como objetos. private, los getters y los setters aparecieron aquí de pasada, pero merecen su propia página: qué protege cada modificador de acceso, cómo se escriben esos métodos según la convención de Java y cuándo conviene no escribirlos — ver Encapsulación: getters, setters y modificadores de acceso.