W3docs

Clases y objetos en Java

Define una clase Java y crea objetos (instancias) a partir de ella, la base del modelo orientado a objetos de Java.

Una clase es una definición; un objeto es una instancia de esa definición que existe en tiempo de ejecución. La clase describe cómo es un perro y qué puede hacer; un objeto es Rex, un perro específico que vive en memoria mientras tu programa se ejecuta. Todo lo que veremos a continuación se basa en esa distinción.

Definir una clase

La definición de una clase reside en su propio archivo .java, con el nombre de la clase. El cuerpo contiene campos (los datos que lleva cada instancia) y métodos (el comportamiento que cada instancia puede realizar).

public class Dog {
  String name;
  int    age;

  void describe() {
    System.out.println(name + ", age " + age);
  }
}

Esto declara un tipo. Aún no crea ningún perro — exactamente igual que escribir int no crea un entero.

Crear un objeto con new

La palabra clave new le pide a la JVM que asigne espacio para una instancia y devuelva una referencia a ella:

Dog d = new Dog();

En esa línea ocurren tres cosas:

  1. Asignación. La JVM encuentra espacio en el heap suficientemente grande para un Dog.
  2. Inicialización por defecto. Cada campo recibe un valor por defecto — null para objetos, 0 para enteros, false para booleanos.
  3. Llamada al constructor. Los () invocan un constructor. No escribimos ninguno, así que Java suministró un constructor sin argumentos por defecto que no hace nada extra. El siguiente capítulo sobre constructores cubre cómo escribir los propios.

Después de esto, d contiene una referencia — un valor pequeño que apunta al objeto en el heap. El objeto en sí es algo más grande que reside en el heap.

Leer y escribir campos

Se accede a un campo escribiendo <referencia>.<campo>:

d.name = "Rex";
d.age  = 3;
System.out.println(d.name);   // Rex

El acceso a campos también es la forma de llamar a métodos:

d.describe();    // Rex, age 3

El punto es el mismo en ambos casos; si el lado derecho es un campo o un método depende simplemente de lo que sigue.

Las referencias no son el objeto

Esta es la frase más importante de este capítulo: una variable de tipo clase contiene una referencia, no el objeto en sí.

Dog a = new Dog();
a.name = "Rex";

Dog b = a;           // copies the REFERENCE, not the dog
b.name = "Buddy";

System.out.println(a.name);   // Buddy

a y b apuntan al mismo objeto en el heap, por lo que modificarlo a través de uno es visible a través del otro. Compara con los primitivos:

int x = 5;
int y = x;       // copies the value
y = 9;
System.out.println(x);    // still 5

x e y son independientes — los primitivos se copian por valor. El capítulo sobre paso por valor profundiza en lo que esto significa para los argumentos de método.

null y NullPointerException

Una variable de referencia puede ser null, lo que significa "no apunta a ningún objeto":

Dog d = null;
d.describe();    // NullPointerException

null es lo que obtienes si nunca asignaste un objeto, o si un campo de tipo objeto nunca fue inicializado explícitamente. Desreferenciar null (escribir d.algo cuando d == null) lanza una NullPointerException en tiempo de ejecución. Escribir código que no falle con null es la mitad del Java práctico.

Advertencia
NullPointerException es un error en tiempo de ejecución, no un error de compilación — el código compila correctamente y solo falla cuando esa línea realmente se ejecuta. La solución es asegurarse de que la variable apunte a un objeto real primero (d = new Dog();) o protegerla con una verificación (if (d != null) d.describe();) antes de desreferenciarla.

Comparar objetos: == vs equals

Para referencias, == pregunta "¿apuntan estas dos variables al mismo objeto?":

Dog a = new Dog();
Dog b = new Dog();
Dog c = a;

System.out.println(a == b);   // false — different objects
System.out.println(a == c);   // true  — same object

Si quieres comparar el contenido de dos objetos, llamas a un método equals en su lugar — cada clase hereda uno por defecto de Object, pero el predeterminado simplemente hace igualdad de referencia. Puedes sobrescribir equals para que signifique lo que quieras; consulta el capítulo equals & hashCode más adelante en esta parte.

Un archivo, muchos objetos

Una sola definición de clase admite instancias ilimitadas. Todas comparten el diseño pero cada una tiene su propio estado:

Dog rex   = new Dog();   rex.name   = "Rex";   rex.age   = 3;
Dog molly = new Dog();   molly.name = "Molly"; molly.age = 7;

rex.describe();     // Rex, age 3
molly.describe();   // Molly, age 7

Un método como describe lee de this — el objeto sobre el que fue llamado — por lo que el mismo código imprime una salida diferente según la instancia en la que se llame.

Dónde viven las clases

Un archivo .java que declara public class Dog debe llamarse Dog.java. Puedes tener clases no públicas en el mismo archivo, pero solo una clase public por archivo, y su nombre debe coincidir con el nombre del archivo. Para los programas pequeños de este capítulo, a menudo pondremos clases auxiliares dentro del mismo archivo que main usando clases anidadas static, solo para mantener el ejemplo en un solo archivo.

Un ejemplo completo

java— editable, runs on the server

Qué sigue

Ya puedes declarar una clase e instanciarla, pero hasta ahora el único campo que has escrito ha sido "cualquier valor sirve". El siguiente capítulo sobre atributos de clase explica los campos en detalle — declaración, valores por defecto, ámbito de instancia vs clase, y las convenciones que sigue el código Java.

Práctica

Práctica
Dado Dog a = new Dog(); Dog b = a; b.name = 'Rex'; — ¿qué imprime System.out.println(a.name)?
Dado Dog a = new Dog(); Dog b = a; b.name = 'Rex'; — ¿qué imprime System.out.println(a.name)?
Was this page helpful?