W3docs

Atributos de clases en Java (Fields)

Declara campos de instancia en una clase Java, establece sus valores iniciales y accede a ellos a través de objetos.

Los atributos de una clase son las variables declaradas dentro de ella — los datos que lleva cada objeto. La mayoría de los autores los llaman fields (así los denomina la Especificación del Lenguaje Java), y "atributo" es la palabra más general de la programación orientada a objetos; ambos significan lo mismo. Este capítulo trata sobre cómo declararlos, qué valores tienen al inicio y cómo leerlos y escribirlos desde fuera de la clase.

Declarar un campo

Un campo se parece a una variable local, pero reside en el cuerpo de la clase en lugar de dentro de un método:

public class Book {
  String title;
  String author;
  int    pages;
  boolean inPrint;
}

Cada instancia de Book obtiene su propia copia de estos cuatro campos. Dos libros tienen dos strings title separados, dos ints pages separados, etc. Existen durante el tiempo de vida del objeto, es decir, hasta que nada lo referencia.

Valores por defecto

Si no inicializas un campo, Java lo inicializa por ti. Los valores por defecto dependen del tipo:

TipoValor por defecto
byte, short, int, long0
float, double0.0
char'�' (el carácter nulo, punto de código 0 — no es un espacio)
booleanfalse
cualquier tipo de objetonull
Book b = new Book();
System.out.println(b.title);    // null
System.out.println(b.pages);    // 0
System.out.println(b.inPrint);  // false

Esta es una diferencia fundamental entre los campos y las variables locales dentro de los métodos — las variables locales no tienen valor por defecto, y el compilador no permite leerlas antes de asignarles un valor. Los campos siempre comienzan con algo.

Inicializadores en línea

Puedes asignar un valor a un campo justo donde lo declaras:

public class Book {
  String title   = "Untitled";
  int    pages   = 0;
  boolean inPrint = true;
}

El inicializador se ejecuta una vez por objeto, cuando ese objeto es creado. Se ejecuta en orden de declaración, antes del cuerpo del constructor. Si un campo necesita una configuración más compleja, esa es la tarea del constructor.

Leer y escribir campos

Usas <referencia>.<campo> desde fuera, y simplemente <nombreCampo> (o this.<nombreCampo>) desde dentro de la clase:

Book b = new Book();
b.title = "Effective Java";    // write
String t = b.title;            // read

Dentro de la clase:

public class Book {
  String title;
  void rename(String t) {
    title = t;             // same as this.title = t;
  }
}

El capítulo sobre la palabra clave this explica cuándo necesitas el calificador explícito this. y cuándo no.

Convenciones de nomenclatura

Los nombres de campos en Java usan lowerCamelCase:

String firstName;       // good
String first_name;      // not Java style
String FirstName;       // looks like a class

Los booleanos suelen nombrarse con los prefijos is o has (isPublished, hasIndex), lo que hace que los puntos de llamada se lean de forma natural: if (book.isPublished). Las constantes — campos que no cambian — se escriben en UPPER_SNAKE_CASE y se marcan como static final, lo cual se cubre en los capítulos de static y final.

Campos de instancia vs. campos de clase

Por defecto, los campos pertenecen a cada instancia — cada objeto tiene su propia copia. Al agregar static, el campo pertenece a la clase misma; existe exactamente una copia, compartida entre todas las instancias:

public class Counter {
  int count;            // instance — each Counter has its own
  static int total;     // class    — one shared by all Counters
}

Counter a = new Counter();
Counter b = new Counter();
a.count++;   b.count++;   b.count++;
Counter.total++;

System.out.println(a.count);          // 1
System.out.println(b.count);          // 2
System.out.println(Counter.total);    // 1, accessed through the class

Conocerás la historia completa en el capítulo sobre static; por ahora, considera que todo campo es un campo de instancia a menos que esté marcado explícitamente como static.

Los campos públicos suelen ser un error

Java permite escribir public String title; y dejar que el código externo lo modifique directamente. En la práctica, casi nunca se hace. Una vez que un campo es público, pierdes la capacidad de validar las escrituras, cambiar el tipo más adelante o envolver las lecturas con lógica — cualquiera que toque el campo está ligado a su representación actual.

El patrón estándar es marcar los campos como private y exponer getters y setters en su lugar:

public class Book {
  private String title;

  public String getTitle()          { return title; }
  public void   setTitle(String t)  { this.title = t; }
}

Esto es encapsulación. Los capítulos sobre encapsulación y getters y setters cubren el patrón completo. En los primeros ejemplos mostramos los campos directamente para mayor claridad, pero el código Java real los mantiene privados.

Los campos contienen referencias, no objetos

Cuando el tipo de un campo es una clase (no un primitivo), el campo es una referencia. Dos objetos pueden compartir el mismo objeto subyacente a través de sus campos:

public class Author { String name; }
public class Book   { Author author; }

Author a = new Author();
a.name = "Joshua Bloch";

Book b1 = new Book();   b1.author = a;
Book b2 = new Book();   b2.author = a;     // same Author object

a.name = "J. Bloch";
System.out.println(b1.author.name);   // J. Bloch
System.out.println(b2.author.name);   // J. Bloch

Las mismas advertencias del capítulo anterior se aplican aquí: esto a veces es lo que deseas y a veces es un error. Si un Book debe tener su propio Author, asignarías new Author() a cada uno.

Un ejemplo práctico

java— editable, runs on the server

Qué sigue

Los campos son el estado de un objeto. La otra mitad — su comportamiento — reside en los métodos declarados en la clase. El próximo capítulo sobre métodos de clase muestra cómo adjuntar métodos a las instancias y cómo acceden a los campos que acabas de definir.

Práctica

Práctica
Un campo de instancia de tipo int se declara pero nunca se asigna. ¿Qué valor tiene cuando lo lees a través de un objeto recién creado?
Un campo de instancia de tipo int se declara pero nunca se asigna. ¿Qué valor tiene cuando lo lees a través de un objeto recién creado?
Was this page helpful?