- Aprender
- Informática
- Programación
- Programación orientada a objetos con Java
- Clases y objetos en Java
Clases y objetos en Java
toString legible y termina diseñando, creando y probando una clase completa a partir de una breve descripción.PrincipianteUnidad 5 de 11 del curso Curso de Programación orientada a objetos con Java
Lo que aprenderás
- Explica cómo una clase define un nuevo tipo de datos con su propio comportamiento, y crea y utiliza objetos de ese tipo en un programa.
- Explica qué son una clase y un objetoDescribe una clase como la definición de un tipo, un objeto como una instancia de ese tipo y el estado y el comportamiento como lo que los objetos almacenan y hacen.
- Crea objetos y llama a sus métodosCrea objetos con
new, llama a sus métodos mediante la notación de punto y predice cómo se comportan objetos distintos.
- Explica qué son una clase y un objeto
- Declara las variables de instancia que almacenan el estado de un objeto y escribe constructores que den a cada objeto nuevo valores iniciales válidos.
- Declara variables de instanciaDeclara campos con tipos adecuados, conoce sus valores predeterminados y distínguelos de las variables locales y los parámetros.
- Escribe constructores que inicialicen objetosEscribe constructores que asignen valores a todos los campos, utiliza
thispara distinguir los campos de los parámetros y evita los errores que dejan campos sin asignar. - Ofrece varios constructores y encadénalosSobrecarga constructores para distintas formas de crear un objeto y utiliza
this(...)para escribir el código de inicialización una sola vez.
- Declara variables de instancia
- Escribe métodos de instancia que lean y modifiquen el estado de un objeto, sigue su efecto y decide cuándo algo pertenece a un objeto o a la clase en su conjunto.
- Escribe métodos de instancia que utilicen y modifiquen el estadoEscribe métodos que informen sobre los campos de un objeto o los modifiquen, llama a otros métodos del mismo objeto y sigue el estado de los objetos paso a paso.
- Distingue los miembros de instancia de los miembros estáticosUtiliza
thispara el objeto actual, decide qué debería ser estático y corrige los errores que surgen al mezclar código estático y de instancia.
- Escribe métodos de instancia que utilicen y modifiquen el estado
- Oculta los campos mediante modificadores de acceso, proporciona acceso controlado mediante métodos de acceso, métodos modificadores y métodos con una función clara, y mantén cada objeto en un estado válido.
- Oculta datos con modificadores de accesoUtiliza
private, acceso de paquete,protectedypublicpara controlar qué código puede utilizar los miembros de una clase, y explica por qué los campos se mantienen privados. - Escribe métodos de acceso y métodos modificadoresEscribe métodos de acceso y modificadores con los nombres estándar, y decide qué campos los necesitan y cuándo es mejor un método con una función clara.
- Mantén los objetos en un estado válido mediante comprobacionesDefine las reglas que debe cumplir el estado de un objeto, aplícalas en constructores y métodos y evita entregar datos internos que permitan eludir esas comprobaciones.
- Oculta datos con modificadores de acceso
- Da a los objetos una forma textual legible con
toStringy después diseña, escribe y prueba una clase completa a partir de una breve descripción.- Escribe un método toStringEscribe un método
toStringque devuelva una descripción legible de un objeto y reconoce cuándo Java lo llama automáticamente. - Diseña, crea y prueba una clase completaConvierte una breve descripción en una clase con campos, constructores, métodos y reglas, y después prueba cada comportamiento desde un programa principal.
- Escribe un método toString
Guía de estudio de Clases y objetos en Java
1Clases, objetos y llamadas a métodos
Un programa suele necesitar mantener juntos varios valores relacionados: por ejemplo, el nombre, la especie y la edad de una mascota. Una clase da un tipo a ese grupo y reúne en un mismo lugar las acciones que lo utilizan. Relacionarás las definiciones de clases con los objetos creados mientras se ejecuta un programa y después seguirás las llamadas a métodos para ver qué datos de cada objeto cambian. Distinguir una clase, un objeto y una variable te ayudará a leer el código que escribirás a continuación.
1.1 Un tipo con estado y comportamiento
Una clase define un tipo: los datos que recuerdan sus objetos y las operaciones que ofrecen. Un objeto, también llamado instancia, es un valor de ese tipo creado mientras se ejecuta un programa. Escribir la definición de una clase no crea un objeto.
Estado y comportamiento
El nombre, la especie y la edad de una mascota forman su estado. Esos valores actuales se guardan en variables de instancia, también llamadas campos. Una operación como celebrar un cumpleaños es un comportamiento, escrito como método. El método de cumpleaños está junto a la edad que modifica, por lo que la regla se mantiene en un solo lugar.
Piensa en una clase como el plano de una construcción. Muchas casas pueden seguir un mismo plano, pero cada una tiene su propio contenido. Del mismo modo, dos mascotas pueden seguir la misma definición y tener edades distintas. Escribes los nombres de los campos una sola vez; cada objeto obtiene sus propios valores.
Lee una clase pequeña
public class Pet {
private String name;
private String species;
private int age;
public Pet(String name, String species, int age) {
this.name = name;
this.species = species;
this.age = age;
}
public void celebrateBirthday() {
this.age++;
}
}
Lee esto de fuera hacia dentro. public class Pet introduce el tipo y las llaves exteriores contienen su definición. Las tres primeras declaraciones describen el estado. El bloque llamado Pet es un constructor: da a un objeto nuevo sus primeros valores. celebrateBirthday es un método: aumenta la edad del objeto actual. Las palabras private y public controlan el acceso; los ejemplos posteriores las utilizan para proteger el estado.
Los parámetros del constructor son valores que se proporcionan al crear un objeto. En this.age = age;, el lado izquierdo designa el campo del objeto y el derecho designa el parámetro proporcionado. El constructor almacena esa entrada para que el objeto pueda recordarla una vez terminada la construcción.
Pon una clase a trabajar
Ya has utilizado clases de bibliotecas. Scanner describe objetos que leen datos de entrada, ArrayList describe listas y un objeto String ofrece operaciones como length(). Una clase que escribes sigue la misma idea básica: pone un tipo útil a disposición del resto de tu programa.
Sin Pet, un programa podría pasar un nombre, una especie y una edad por separado a muchos métodos. Debe mantener correctamente unido cada grupo. Un objeto Pet lleva los valores relacionados como una sola unidad. Los métodos de ese objeto saben qué edad deben utilizar.
Organiza y nombra el código
En los archivos de código fuente habituales, una clase pública llamada Pet se guarda en Pet.java, con las mismas mayúsculas. Una clase Main separada puede contener el método main del programa, crear mascotas y llamar a sus métodos. Pet no necesita un main propio. Las clases del mismo paquete sin nombre pueden utilizarse entre sí sin importaciones; los ejemplos sencillos mantienen esas clases en una carpeta.
Utiliza sustantivos en UpperCamelCase para las clases, como LibraryBook. Utiliza lowerCamelCase para campos y métodos: pageCount nombra datos; giveBack() nombra una acción. Son convenciones que ayudan a quien lee a reconocer cada parte, aunque el compilador permita muchos otros nombres.
Puntos clave
- Una clase define un tipo; un objeto es una instancia creada mientras se ejecuta el programa.
- Los campos almacenan el estado y los métodos proporcionan el comportamiento.
- Los objetos de una clase siguen la misma definición y almacenan sus propios valores de campos de instancia.
- Una clase pública en un archivo de código fuente habitual utiliza el nombre correspondiente de la clase como nombre de archivo.
1.2 Objetos nuevos y las referencias que permiten acceder a ellos
Crear un objeto y declarar una variable son operaciones distintas. Una variable te da un nombre mediante el que acceder a un objeto; new crea el objeto al que hará referencia ese nombre.
Lee una sentencia de creación de objetos
Pet luna = new Pet("Luna", "cat", 3);
Pet es el tipo de la variable y luna es su nombre. new Pet(...) crea un objeto nuevo y llama a un constructor compatible con tres argumentos. El constructor almacena el nombre, la especie y la edad. La referencia resultante se asigna a luna.
Una referencia indica a Java qué objeto debe utilizar. Es útil dibujar una variable como un nombre con una flecha hacia un objeto. La variable no es una segunda copia de todos los campos del objeto.
Llama a un método de un objeto concreto
El punto en luna.celebrateBirthday() conecta una referencia con un método que se ejecuta sobre su objeto. Un método que devuelve un valor puede proporcionarlo a otra expresión:
luna.celebrateBirthday();
int years = luna.getAge();
System.out.println(years); // 4
Aquí getAge() es un método público que devuelve la edad de la mascota. La llamada de cumpleaños cambia el estado; el método de acceso lee ese estado. Pet.celebrateBirthday() falla porque este método de instancia necesita una mascota concreta. El nombre de la clase por sí solo no responde de quién es el cumpleaños.
Objetos separados y referencias compartidas
Pet max = new Pet("Max", "dog", 5);
luna.celebrateBirthday();
System.out.println(luna.getAge()); // 5
System.out.println(max.getAge()); // 5
Luna ya tenía 4 años, así que el siguiente cumpleaños la lleva a 5. Max sigue teniendo 5. Tener la misma edad no hace que sean el mismo objeto: las dos expresiones new crearon mascotas distintas.
Considera ahora una asignación sin new:
Pet other = luna;
other.celebrateBirthday();
System.out.println(luna.getAge()); // 6
La asignación copia la referencia de Luna. Ambos nombres acceden a una sola mascota, por lo que cambiarla mediante other es visible mediante luna. Para crear una segunda mascota, llama de nuevo a new.
Haz coincidir los parámetros del constructor
Los argumentos deben ajustarse al número, orden y tipos de los parámetros de un constructor declarado. Si el único constructor disponible recibe (String, String, int), new Pet() no compila. Java no adivina los valores que faltan. Sin embargo, intercambiar las dos cadenas sí compila: new Pet("cat", "Luna", 3) proporciona los tipos correctos, pero los significados equivocados. Lee los nombres de los parámetros para comprobar ese orden.
Estos dos intentos incompletos fallan por distintas razones:
Pet a; // declaration only
// System.out.println(a.getAge()); // a has no assigned value
// Pet b = Pet("Bo", "cat", 2); // missing new
Una variable local debe tener un valor asignado antes de utilizarse. Sin new, Java busca un método llamado Pet, no una expresión de creación de objetos. Una vez que existe un objeto, al imprimirlo puede mostrarse un texto como Pet@8bcc55f hasta que proporciones un método toString() legible; esa salida no significa que la construcción haya fallado.
Puntos clave
- Utiliza new con argumentos que coincidan con un constructor disponible.
- La notación de punto llama a un método de instancia sobre el objeto al que accede una referencia.
- Otra expresión new crea otro objeto; la asignación de una referencia comparte uno existente.
- Los argumentos del mismo tipo pueden intercambiarse sin producir un error del compilador, así que comprueba sus significados.
- Una declaración local por sí sola no crea ningún objeto ni da a la variable un valor utilizable.
2Campos y estado inicial de un objeto
Los objetos necesitan un lugar donde guardar sus datos y una forma fiable de obtener sus primeros valores. Los campos proporcionan el almacenamiento; los constructores inicializan cada objeto nuevo. Elegirás tipos de campos, separarás el estado duradero del trabajo local temporal y seguirás la construcción desde los valores predeterminados hasta obtener un objeto listo para usar. Después ofrecerás varias formas útiles de crear el mismo tipo de objeto, manteniendo la inicialización y las comprobaciones compartidas en un solo lugar.
2.1 Datos que recuerda un objeto
Un objeto necesita un campo para cada valor que debe recordar entre llamadas a métodos. Elige esos valores antes de escribir los métodos: forman el estado duradero del objeto.
Declara campos con tipos adecuados
Un campo se encuentra dentro de las llaves de la clase, pero fuera de todos los constructores y métodos. Una declaración necesita un tipo y un nombre; también pueden aparecer un modificador de acceso y un inicializador.
private String title;
private int pageCount;
private boolean lentOut = false;
String es adecuado para texto, int para un recuento de números enteros y boolean para una condición de sí o no. Los campos también pueden utilizar tipos de clase como ArrayList<String>. Estos ejemplos utilizan private; omitir el modificador da acceso de paquete, no acceso privado.
Cada objeto obtiene una copia separada de cada campo de instancia. Dos objetos Rectangle tienen cada uno un width y un height, aunque las declaraciones aparezcan una sola vez en la clase.
Los valores predeterminados no siempre son valores iniciales utilizables
| Tipo de campo | Valor predeterminado |
|---|---|
int, long | 0 |
double | 0.0 |
boolean | false |
Tipos de clase, incluidos String y ArrayList | null |
Se asigna un valor predeterminado a un campo cuando se crea el espacio de almacenamiento del objeto. Puede que no se ajuste a la finalidad del objeto. Un campo de tipo lista con el valor null no es una lista vacía: todavía necesitas crear la lista antes de añadir un elemento.
Las variables locales no reciben ese valor predeterminado. Dentro de un método, int total; seguido de System.out.println(total); no compila porque no se ha asignado un valor a total. Distingue la regla de los campos de la de las variables locales.
Decide qué debe perdurar
| Tipo de variable | Dónde se declara | Para qué sirve |
|---|---|---|
| Campo de instancia | En la clase, fuera de los métodos | Valores que recuerda un objeto |
| Parámetro | En la cabecera de un constructor o método | Entradas para esa llamada |
| Variable local | Dentro de un bloque de método o constructor | Trabajo temporal para esa llamada |
Un campo permanece con su objeto. Un parámetro está disponible durante su llamada y una variable local está disponible en su bloque mientras se ejecuta esa llamada. Si un contador debe conservar su cuenta de una llamada a la siguiente, la cuenta pertenece a un campo. Un subtotal temporal utilizado para un cálculo puede ser local.
Almacena las entradas; calcula los valores derivados
public class Rectangle {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
public double area() {
return this.width * this.height;
}
}
Las dimensiones están en centímetros, por lo que area() devuelve un área en centímetros cuadrados. Almacenar un campo separado para el área crearía otro valor que habría que actualizar cada vez que cambiara una dimensión. Calcularlo a partir de las dimensiones mantiene la coherencia del resultado.
Utiliza un campo de instancia final para un valor que se asigna una sola vez, como private final String title;. Asígnale un valor en su declaración o en cada constructor. final impide la reasignación. static tiene otro significado: crea un campo de clase compartido. Añadir static al nombre de una mascota haría que distintas mascotas compartieran una sola variable de nombre.
Puntos clave
- Los campos de instancia se declaran fuera de los métodos y recuerdan el estado de cada objeto.
- Los campos reciben valores predeterminados; a las variables locales se les debe asignar un valor antes de usarlas.
- Elige campos para los datos duraderos y variables locales para el trabajo temporal.
- Calcula los valores que se derivan de campos almacenados para evitar copias incoherentes.
- Un campo de instancia final se asigna una vez; un campo estático es compartido por la clase.
- Un campo de tipo lista con valor null sigue necesitando un objeto de lista antes de poder utilizarse.
2.2 De los argumentos a los campos inicializados
Un constructor inicializa un objeto cuando new lo crea. Su nombre debe coincidir con el de la clase y no tiene tipo de retorno. Incluso void convertiría la declaración en un método.
Transfiere las entradas al estado
public Pet(String name, String species, int age) {
this.name = name;
this.species = species;
this.age = age;
}
Un constructor suele aceptar entradas como parámetros y almacenarlas en campos. Aquí cada parámetro tiene el mismo nombre que su campo. El nombre age por sí solo designa el parámetro; this.age designa el campo del objeto que se está creando. La asignación lee el valor proporcionado a la derecha y escribe el campo de la izquierda.
Para new Pet("Luna", "cat", 3), primero los campos del objeto nuevo reciben valores predeterminados: null, null y 0. Después el constructor recibe los tres argumentos y sustituye esos valores. Cuando termina la construcción, new produce la referencia que almacena quien lo llamó.
Dos errores que compilan
public Pet(String name, String species, int age) {
name = name;
this.species = species;
this.age = age;
}
Ambas apariciones de name hacen referencia al parámetro, por lo que la primera línea asigna ese parámetro a sí mismo. El nombre del objeto permanece en null. El código es válido, por eso es importante comprobar los valores del objeto nuevo.
Una declaración dentro del constructor causa un problema relacionado:
String nick = initialNick;
Si ya existe un campo llamado nick, esta línea crea una variable local con el mismo nombre. La variable local desaparece cuando termina la construcción. Escribe this.nick = initialNick; para almacenar la entrada en el campo; no repitas el tipo.
Identifica cuándo existe un constructor sin argumentos
Si una clase no declara constructores, Java proporciona un constructor predeterminado sin parámetros. En una clase sencilla, sus campos conservan sus inicializadores declarados o valores predeterminados. En cuanto declaras cualquier constructor, Java deja de proporcionar ese constructor predeterminado.
Por tanto, una clase que solo tiene Pet(String name, String species, int age) no puede crearse con new Pet(). Añade un constructor explícito sin argumentos solo cuando exista un estado inicial útil para él. Presta atención también a public void Pet(...): es un método, por lo que no proporciona el constructor previsto.
Establece también los valores iniciales internos
No todos los campos tienen que proceder de un argumento. Un libro nuevo siempre puede empezar con this.lentOut = false;. Una clase que posee una lista puede inicializarla así, con ArrayList importado:
private ArrayList<String> tracks;
public Playlist() {
this.tracks = new ArrayList<>();
}
La lista vacía está lista para add. Dejar tracks en null hace que una llamada posterior a tracks.add(...) falle con NullPointerException.
Un inicializador de campo se ejecuta antes del cuerpo del constructor. Si private int score = 10; va seguido de this.score = 5; en el constructor, la puntuación del objeto terminado es 5. Prueba los valores después de la construcción, no solo los valores escritos junto a las declaraciones de los campos. Los constructores también necesitan las mismas reglas de validación que los cambios posteriores, para que el primer estado sea válido.
Puntos clave
- Un constructor tiene el nombre de la clase y no tiene tipo de retorno.
- Utiliza this.field = parameter cuando los nombres coincidan.
- Ni la autoasignación de un parámetro ni una nueva variable local inicializan el campo previsto.
- Java proporciona un constructor predeterminado solo cuando la clase no declara constructores.
- Inicializa el estado interno, como las listas vacías, y aplica la validación durante la construcción.
2.3 Varias formas de construir un mismo tipo de objeto
Una clase puede ofrecer varias formas útiles de crear un objeto. La sobrecarga de constructores consiste en declarar constructores con distintas listas de parámetros.
Distingue los constructores por sus parámetros
Java distingue los constructores por el número, los tipos y el orden de sus parámetros. Los nombres de los parámetros no los distinguen. Box(String label) y Box(String name) describen la misma lista de parámetros, por lo que no pueden declararse ambos en una misma clase.
Una mascota puede crearse con una edad o como recién nacida:
public Pet(String name, String species, int age) {
this.name = name;
this.species = species;
this.age = age;
}
public Pet(String name, String species) {
this(name, species, 0);
}
new Pet("Pip", "rabbit") selecciona el constructor de dos parámetros. Ese constructor proporciona 0 como edad que falta y llama al constructor de tres parámetros. El objeto nuevo termina con el estado "Pip", "rabbit" y 0.
Encadena la inicialización del mismo objeto
Dentro de un constructor, this(...) llama a otro constructor de la misma clase. El constructor más breve elige los valores predeterminados; el más completo realiza la inicialización compartida. Las comprobaciones situadas en esa inicialización se aplican a ambas vías de construcción.
Compara dos líneas que se parecen:
| Línea dentro de un constructor | Efecto |
|---|---|
this(name, species, 0); | Inicializa el objeto actual mediante otro constructor |
new Pet(name, species, 0); | Crea una mascota distinta |
La segunda línea no rellena los campos del objeto actual. Si su resultado nunca se almacena, esa mascota adicional se descarta. La mascota actual puede seguir teniendo campos con null.
Sigue una cadena antes de recorrer el código posterior
Un reloj puede ofrecer la medianoche como valor predeterminado:
public Clock() {
this(0, 0);
}
public Clock(int hours, int minutes) {
this.hours = hours;
this.minutes = minutes;
}
Para new Clock(), entra en el constructor sin argumentos, sigue this(0, 0) y asigna ambos campos en el constructor de dos argumentos. Después el control regresa al constructor sin argumentos. Esto crea un reloj, no dos. Una llamada a new Clock(9, 5) comienza directamente en el constructor más completo.
Mantén la cadena válida y clara
Un constructor puede contener como máximo una llamada a this(...). La cadena debe llegar finalmente a una inicialización que no vuelva a llamar a la cadena: dos constructores que delegan el uno en el otro producen un error de compilación por constructor recursivo.
Poner this(...) primero es un estilo claro que funciona en todas las versiones de Java. En Java 24 y versiones anteriores sin características preliminares, debe ir primero. Java 25 permite sentencias anteriores para tareas como calcular o comprobar argumentos. Esas sentencias no pueden leer los campos de instancia del objeto actual ni llamar a sus métodos de instancia; se permiten asignaciones a campos declarados en la clase sin inicializadores en su declaración.
Ofrece sobrecargas porque quienes llaman disponen de distintas entradas útiles. Un reloj que empieza a medianoche tiene sentido; un libro sin título puede que no. La existencia de un constructor completo no crea automáticamente sobrecargas más breves.
Puntos clave
- Los constructores sobrecargados se distinguen por sus listas de parámetros, no por los nombres de estos.
- La llamada this(...) delega en otro constructor sobre el mismo objeto.
- Mantén la inicialización y las comprobaciones compartidas en una sola vía de construcción.
- Una cadena de constructores no debe volver a un constructor que ya esté en esa cadena.
3Métodos que leen y modifican el estado
Un objeto útil puede responder preguntas sobre sí mismo y realizar acciones que modifiquen su estado. Los métodos de instancia sitúan esas operaciones junto a los campos que utilizan. Seguirás los cambios sentencia por sentencia, manejarás el cambio de hora de un reloj y devolverás valores que otro código pueda utilizar. También decidirás qué datos pertenecen a cada objeto y qué datos u operaciones pertenecen a la clase, para que los objetos distintos sigan siendo independientes.
3.1 Cálculos, cambios y seguimiento del estado
Un método de instancia se ejecuta para un objeto concreto. Decláralo sin static y utiliza los campos de ese objeto mediante nombres como this.width. Decide qué necesita quien lo llama: un cambio de estado, un resultado devuelto o ambas cosas.
Devuelve cálculos; haz explícitos los cambios de estado
Para un rectángulo cuyas dimensiones se almacenan en centímetros:
public double area() {
return this.width * this.height;
}
public double perimeter() {
return 2 * (this.width + this.height);
}
public void scale(double factor) {
this.width = this.width * factor;
this.height = this.height * factor;
}
Un rectángulo con lados de 3,0 y 4,0 tiene un área de 12,0 centímetros cuadrados y un perímetro de 14,0 centímetros. scale(2) cambia los lados a 6,0 y 8,0. Las siguientes llamadas devuelven un área de 48,0 y un perímetro de 28,0. Cada método lee los campos actuales, por lo que no es necesario actualizar un área almacenada.
area() devuelve un número que puede almacenarse o utilizarse en un cálculo. Si solo imprimiera el número y tuviera el tipo de retorno void, quien lo llama no podría escribir double twice = r.area() * 2;. Deja la impresión a quien llama al método cuando la función de este sea calcular un valor.
Actualiza los campos relacionados en orden
El método advance() de un reloj debe gestionar tanto el cambio de minuto como el de hora:
public void advance() {
this.minutes++;
if (this.minutes == 60) {
this.minutes = 0;
this.hours++;
if (this.hours == 24) {
this.hours = 0;
}
}
}
A las 23:58, la primera llamada llega a 23:59 y omite ambos bloques de reinicio. La siguiente llamada llega brevemente al minuto 60, lo reinicia a 0, aumenta la hora a 24 y la reinicia a 0. El estado final es 00:00. Una llamada más da 00:01.
Sigue los objetos por separado
Escribe una fila después de cada sentencia y una columna para los campos de cada objeto. Cambia solo el objeto indicado por el receptor de la llamada. Para mascotas de 2 y 7 años, dos cumpleaños de la primera y setAge(1) en la segunda dejan las edades en 4 y 1. No ejecutes el cuerpo de un método para cada instancia solo porque comparten una clase.
Una declaración local puede ocultar el campo que querías actualizar. public void reset() { int count = 0; } solo crea una variable temporal. this.count = 0; reinicia el contador duradero.
Reutiliza métodos y completa las rutas de retorno
Dentro de un método de instancia, area() y this.area() llaman al método de área del mismo objeto. Un método de descripción puede reutilizar ese cálculo en lugar de copiar su expresión. Un método también puede cambiar el estado y devolver si tuvo éxito, como hace lend() cuando marca un libro como prestado e indica true.
Un método que no es void no puede simplemente llegar al final sin devolver un valor compatible. Si get() solo devuelve un valor dentro de if (count > 0), ¿qué ocurre cuando el contador es 0? Añade la ruta de retorno necesaria o lanza una excepción para un valor que el método rechace. Una ruta que lanza una excepción no regresa a quien llamó al método y no necesita un valor de retorno.
Puntos clave
- Los métodos de instancia leen o modifican el estado del objeto sobre el que se llaman.
- Devuelve los valores calculados para que quienes llaman a los métodos puedan utilizarlos en expresiones.
- Sigue las sentencias en orden y mantén separados los campos de cada objeto.
- Los métodos que gestionan cambios de unidad deben devolver cada campo relacionado a su rango permitido.
- Reutiliza otros métodos del mismo objeto llamándolos directamente o con this.
- Un método que devuelve un valor necesita uno en cada ruta que retorna normalmente.
3.2 Miembros de cada objeto y miembros compartidos de la clase
Pregúntate a quién pertenece un valor o una operación antes de decidir si utilizas static. La edad de una mascota pertenece a una mascota. Un recuento de todas las mascotas creadas pertenece a la clase en su conjunto.
El objeto actual es this
Dentro de un constructor o método de instancia, this hace referencia al objeto que se está construyendo o que recibe la llamada. En this.age++, identifica qué edad cambia. En this.name = name, distingue el campo de un parámetro con el mismo nombre. this(...) es la forma de encadenar constructores.
Un método estático no tiene un objeto actual, por lo que this no puede utilizarse allí. Aun así puede crear un objeto o recibir una referencia y utilizarla para llamar a métodos de instancia.
Campos compartidos y campos de cada objeto
public class Counter {
private int count;
private static int created = 0;
public Counter() {
this.count = 0;
created++;
}
public void increment() {
this.count++;
}
public int getCount() {
return this.count;
}
public static int getCreated() {
return created;
}
}
Después de dos llamadas a new Counter(), hay dos campos count separados, ambos inicialmente en 0, y un campo created igual a 2. Incrementar el primer contador cambia su cuenta a 1; el segundo permanece en 0. Counter.getCreated() sigue devolviendo 2 porque no se ha construido ningún objeto nuevo.
Trabaja a través de un objeto desde main
public static void main(String[] args) {
Counter c = new Counter();
c.increment();
System.out.println(c.getCount());
}
El método main clásico es estático. Una llamada a increment() por sí sola allí no tendría un objeto de destino y no compilaría. La variable c proporciona ese destino. Hacer que count sea estático para eliminar el error cambiaría el diseño: todos los contadores compartirían entonces una sola cuenta.
| Tipo de método | Acceso directo disponible |
|---|---|
| Método de instancia | Sus miembros de instancia y los miembros estáticos de la clase |
| Método estático | Miembros estáticos; miembros de instancia mediante una referencia a un objeto |
Java 25 también admite formas de instancia de main, pero la cabecera estática clásica sigue siendo válida. Estos ejemplos la utilizan de forma coherente.
Elige métodos y constantes de forma deliberada
Una operación que necesita los campos de un objeto debería ser un método de instancia. Una operación que solo depende de sus parámetros puede ser estática, como un método auxiliar que convierte un número total de minutos en horas. Las llamadas estáticas suelen utilizar el nombre de la clase: Math.sqrt(16) o Counter.getCreated().
Un valor fijo compartido suele declararse como constante:
public static final int MAX_CELSIUS = 30;
public lo pone a disposición de quienes llaman, static da a la clase un campo compartido y final impide la reasignación. UPPER_SNAKE_CASE indica una constante por convención. Esta es una excepción habitual a la regla de hacer privados los campos. No utilices static para nombres, dimensiones u otros datos de estado que deban ser distintos entre objetos.
Puntos clave
- La referencia this identifica el objeto actual dentro del código de instancia.
- Los miembros estáticos pertenecen a la clase; los miembros de instancia pertenecen a objetos individuales.
- Un método estático necesita una referencia a un objeto para utilizar miembros de instancia.
- Corrige los errores de contexto estático proporcionando el objeto adecuado cuando el estado pertenece a un objeto.
- Un campo public static final suele proporcionar una constante compartida.
4Acceso controlado y estado válido
Una clase debería controlar los valores que pueden formar parte de su estado. Los campos privados y los métodos públicos permiten a la clase comprobar cada cambio y ofrecer operaciones útiles a quienes la utilizan. Elegirás niveles de acceso, escribirás métodos de acceso y modificadores cuando sean útiles y protegerás reglas como un rango de temperatura permitido. También verás por qué una lista privada puede seguir expuesta mediante un método de acceso y cómo impedir que el código externo eluda las comprobaciones de la clase.
4.1 Estado privado e interfaz pública
La encapsulación mantiene el estado de un objeto junto al código que lo controla. Los campos suelen ser privados, mientras que quienes utilizan el objeto recurren a operaciones públicas. Esto oculta los detalles de almacenamiento y da a la clase un lugar donde aplicar sus reglas.
Elige un nivel de acceso
| Acceso | Quién puede utilizar el miembro |
|---|---|
private | Código de la misma clase |
| Sin modificador | Código del mismo paquete |
protected | El mismo paquete, además del acceso de las subclases según las reglas de Java |
public | Código que puede acceder al tipo que lo declara |
Un paquete agrupa clases. Los ejemplos sencillos sitúan clases habituales juntas sin una declaración package, en un mismo paquete sin nombre. El acceso de paquete se obtiene al omitir el modificador; no hay ninguna palabra clave de acceso package que añadir a un campo.
Empieza con el acceso útil más restringido. Haz que los campos sean privados, que los constructores y operaciones que necesitan otras clases sean públicos y que los métodos auxiliares internos sean privados. Las constantes públicas son una excepción habitual para los campos.
Deja que la clase controle los cambios
Si Pet declara private int age;, una clase Main independiente no puede asignar luna.age = -5;. El compilador rechaza el acceso. Una llamada como luna.setAge(-5) puede permitirse, porque el método público pertenece a Pet y puede decidir si almacena el argumento.
Un campo público permitiría a cualquiera que lo utilice eludir ese método. Cuando todos los cambios pasan por el código de la clase, las comprobaciones pueden estar en un solo lugar. El acceso privado por sí solo no valida una edad; los métodos también deben realizar las comprobaciones.
Mantén estable la interfaz pública
Supón que un reloj almacena inicialmente los campos hours y minutes por separado. Quienes lo utilizan llaman a getHours() y getMinutes(). Más tarde sustituyes los campos por un único valor minutesSinceMidnight:
public int getHours() {
return this.minutesSinceMidnight / 60;
}
public int getMinutes() {
return this.minutesSinceMidnight % 60;
}
Con 615 minutos almacenados, la división devuelve 10 y el resto devuelve 15. El reloj indica 10:15 mediante los mismos métodos. No es necesario reescribir el código que los llama porque dependía de las operaciones públicas, no de cómo se almacenaba el estado. Esta libertad para cambiar los detalles internos es la ocultación de información.
El acceso pertenece a las clases, no a los objetos individuales
El código dentro de Pet puede leer un campo privado de otro objeto Pet. El permiso de acceso procede de estar dentro de la clase. Una clase de nivel superior distinta no obtiene permiso por tener una referencia a una mascota o por estar en la misma carpeta.
Para las declaraciones habituales de clases de nivel superior, las opciones de acceso son public o ningún modificador. Un private class Pet de nivel superior no está permitido. Una clase pública de nivel superior va en el archivo de código fuente correspondiente, y un archivo de código fuente habitual contiene como máximo una clase pública de nivel superior.
Los campos privados son un límite de diseño del programa. Impiden que otro código ordinario dependa directamente de los campos internos, pero no son una forma de mantener un valor en secreto frente a una persona que pueda inspeccionar el programa. Utilízalos para controlar la interfaz de tu clase y proteger su estado.
Puntos clave
- Los campos privados y las operaciones públicas mantienen el control del estado dentro de la clase.
- Omitir un modificador de acceso da acceso de paquete.
- Los métodos públicos permiten cambiar el almacenamiento interno sin cambiar el código que los llama.
- El acceso privado se comprueba por clase, por lo que el código dentro de la clase puede acceder a los campos de otra instancia.
- Las clases habituales de nivel superior utilizan acceso público o de paquete.
4.2 Métodos de acceso adecuados para la clase
Una clase puede permitir que quienes la utilizan lean o cambien determinadas partes de su estado mediante métodos. Decide qué operaciones debería ofrecer la clase antes de crear métodos de acceso y modificadores para cada campo.
Devuelve valores con métodos de acceso
Un método de acceso, también llamado método de consulta, devuelve información sin modificar el objeto. Un método de acceso habitual lee un campo:
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
El tipo devuelto coincide con la información proporcionada. Un método de acceso que imprime y devuelve void no puede proporcionar un valor a una expresión como pet.getAge() + 1. Quien lo llama debería recibir el valor y decidir cómo utilizarlo.
Cambia determinados valores con métodos modificadores
Un método modificador, también llamado método de mutación, recibe un valor nuevo y actualiza el estado:
public void setName(String name) {
this.name = name;
}
this.name es el campo. name es el parámetro. Escribir name = name; compila, pero no cambia ningún campo. Aquí no hay valor de retorno porque la función de este método modificador es realizar un cambio.
Para una mascota de 3 años:
luna.setName("Lulu");
System.out.println(luna.getName() + " is " + luna.getAge());
// Lulu is 3
Quien llama a los métodos nunca toca un campo directamente. El método modificador cambia el nombre y los métodos de acceso devuelven los valores actuales para que quien los llama los combine.
Sigue los nombres que espera otro código Java
| Campo | Método de acceso | Método modificador, si es necesario |
|---|---|---|
pageCount | getPageCount() | setPageCount(int pageCount) |
name | getName() | setName(String name) |
lentOut | isLentOut() | setLentOut(boolean lentOut) |
Escribe en mayúscula la primera letra del nombre del campo después de get, set o el prefijo booleano habitual is. Un nombre como getname() puede compilar, pero no sigue la convención que esperan las herramientas y otros programadores.
Expón solo operaciones útiles
El título de un libro puede tener un método de acceso y ningún método modificador porque quienes lo utilizan deberían poder leerlo, pero no sustituirlo. Un campo privado final puede garantizar que se asigne una sola vez. Un contador interno puede no necesitar ninguno de los dos métodos si solo lo utiliza la clase.
Un método modificador sin comprobaciones puede aceptar el mismo valor perjudicial que un campo público. Añade comprobaciones cuando un cambio tenga restricciones. Considera también un método de acción: celebrateBirthday() expresa el aumento de la edad en uno y lend() expresa un intento de préstamo. lend() puede inspeccionar el estado actual y rechazar un segundo préstamo. Un método modificador también puede realizar esa comprobación; el nombre de la acción hace que la operación resulte más clara para quien la llama.
Un método de acceso puede calcular una respuesta. getArea() puede devolver el producto de la anchura y la altura sin ningún campo area.
Puntos clave
- Un método de acceso devuelve información; un método modificador cambia un valor determinado.
- Sigue el patrón de nombres getName, setName y el habitual isName para booleanos.
- Da a los campos solo los métodos de acceso y modificadores que necesite quien los utiliza.
- Los métodos de acción como lend expresan claramente el comportamiento permitido y pueden comprobar las transiciones.
4.3 Reglas que se mantienen tras cada cambio
Una invariante es una regla sobre el estado de un objeto que se cumple después de la construcción y después de cada operación pública. Un termostato podría permitir temperaturas objetivo de 5 °C a 30 °C. Todas las formas de establecer su temperatura objetivo deben conservar ese rango.
Decide qué significa una entrada no válida
Tres respuestas útiles son conservar el valor anterior, limitar el valor a un extremo permitido o lanzar una excepción. Tienen efectos distintos, así que elige una respuesta clara para cada operación.
| Respuesta | Resultado de una llamada no válida |
|---|---|
| Ignorar | El valor anterior del campo permanece sin cambios |
| Limitar al rango | Se almacena el extremo permitido más cercano |
| Lanzar una excepción | La llamada se detiene con un error como IllegalArgumentException |
Para una edad no negativa de una mascota, un método modificador que ignora valores no válidos puede asignar solo dentro de if (age >= 0). Si la edad almacenada es 4, setAge(-2) la mantiene en 4. No convierte la edad en 0.
Pon las comprobaciones del rango dentro de la clase
public static final int MIN_CELSIUS = 5;
public static final int MAX_CELSIUS = 30;
private int target;
public void setTarget(int celsius) {
if (celsius < MIN_CELSIUS) {
this.target = MIN_CELSIUS;
} else if (celsius > MAX_CELSIUS) {
this.target = MAX_CELSIUS;
} else {
this.target = celsius;
}
}
public void raise() {
setTarget(this.target + 1);
}
Partiendo de 20 °C, setTarget(35) almacena 30. setTarget(-3) almacena 5. Después de setTarget(29), una llamada a raise() almacena 30; otra llamada sigue almacenando 30. Reutilizar el método modificador impide que raise() sobrepase el límite superior.
Las comprobaciones solo en Main no pueden proteger el termostato. Otro código que lo llame podría olvidarlas. La clase debe comprobar la entrada en el lugar donde controla el almacenamiento.
Valida también el primer estado
public Thermostat(int target) {
setTarget(target);
}
Con este constructor que limita al rango permitido, new Thermostat(50) termina en 30 °C. Asignar directamente this.target = target; permitiría el estado inicial no válido de 50. Un método privado de comprobación compartido es otra forma de reutilizar la validación en constructores y métodos posteriores.
Lanzar una excepción es útil cuando un argumento no válido señala un error de programación. Por ejemplo, un constructor puede rechazar un recuento negativo con throw new IllegalArgumentException("count must not be negative");. El objeto no se construye correctamente, por lo que no se entrega a quien lo llamó ningún objeto terminado en un estado no válido. Ignorar la entrada es más sencillo, pero silencioso; quien llama al método puede necesitar otra forma de advertir que nada ha cambiado.
Mantén los datos internos mutables dentro de la clase
Una lista privada puede seguir expuesta si un método de acceso devuelve la lista original. Quien lo llama podría entonces añadir o eliminar entradas sin utilizar los métodos de la clase, eludiendo una regla de tamaño máximo.
Para un campo ArrayList<String> llamado tracks, return new ArrayList<>(this.tracks); proporciona una lista independiente que contiene las mismas cadenas. Cambiar esa lista devuelta no modifica la lista interna. Operaciones como addTrack(String title) pueden mantener los cambios de la lista dentro de la clase y comprobar sus reglas antes de aceptarlos.
Puntos clave
- Una invariante se cumple después de la construcción y después de cada operación pública.
- Ignorar, limitar al rango permitido y lanzar una excepción son respuestas distintas a una entrada no válida.
- Cada constructor y cada método que cambia el estado deben mantener las mismas reglas.
- Reutiliza la validación para que las distintas vías de cambio no puedan eludirla.
- Devolver una lista interna mutable permite a quienes la reciben eludir las comprobaciones de la clase.
- Una copia de una lista interna de cadenas protege la lista original de cambios externos.
5Objetos legibles y clases completas
Las descripciones legibles de los objetos facilitan el uso y la comprobación de una clase. Un método toString proporciona ese texto cuando se imprime un objeto o se une a una cadena. Escribirás el método con la cabecera correcta y después reunirás campos, constructores, métodos y validación en una clase completa. A partir de una breve descripción, convertirás los requisitos en código y probarás llamadas normales, acciones repetidas y casos límite.
5.1 Una descripción del objeto devuelta como texto
Un objeto útil debería ser fácil de inspeccionar como texto. El método incorporado toString() de Java devuelve un nombre de clase, un signo @ y un código hash hexadecimal, como Pet@8bcc55f. Un paquete con nombre pasa a formar parte del nombre de la clase. El texto del hash varía y suele decir poco sobre el estado del objeto.
Devuelve una descripción legible
@Override
public String toString() {
return this.name + " (" + this.species + ", "
+ this.age + " years)";
}
Para Luna, una gata de 3 años, la cadena devuelta es "Luna (cat, 3 years)". El método lee los campos y construye una cadena. No modifica la mascota ni envía salida a la pantalla.
@Override pide al compilador que compruebe que la declaración realmente sustituye un método existente. Eso detecta errores como escribir tostring con una s minúscula. No da formato al resultado por ti; la expresión de retorno determina el texto.
Reconoce las llamadas automáticas
System.out.println(luna);
String label = "Pet: " + luna;
String details = luna.toString();
La primera línea imprime la descripción legible de la mascota. La segunda construye "Pet: Luna (cat, 3 years)". La tercera solicita explícitamente la misma descripción y la almacena sin imprimirla. Cuando se imprime un ArrayList de mascotas, su presentación utiliza el toString() de cada mascota dentro de los corchetes de la lista.
La conversión automática explica por qué es importante devolver texto. Quien llama al método puede estar imprimiendo, almacenando o uniendo el resultado. Un método que solo imprime no puede proporcionar la cadena que necesitan todos esos usos.
Haz coincidir la cabecera del método
| Declaración | Qué ocurre |
|---|---|
public String toString() | Proporciona la descripción del objeto |
public String tostring() | Declara un método distinto; @Override lo detecta |
public String toString(int width) | Declara un método sobrecargado; la impresión automática no lo llama |
public void toString() | Falla: entra en conflicto con el método existente que devuelve String |
Utiliza la cabecera exacta sin argumentos e incluye la anotación. Un método sobrecargado con parámetros puede ser un método independiente válido, pero imprimir un objeto no proporciona esos parámetros.
Da formato a los valores sin cambiarlos
Un reloj necesita horas y minutos de dos dígitos. Dentro de su método toString():
return String.format(java.util.Locale.US,
"%02d:%02d", this.hours, this.minutes);
Para 9 horas y 5 minutos, la cadena es "09:05". Cada %02d da formato a un entero en al menos dos posiciones, utilizando un cero inicial cuando es necesario. String.format(java.util.Locale.US, "%.2f", 7.5) devuelve "7.50". Proporcionar la configuración regional hace que la salida con punto decimal sea independiente de la configuración regional de formato predeterminada del equipo.
Mantén la descripción lo bastante breve para leerla durante la depuración. Puede revelar un estado sin inicializar: unir un campo de nombre null a una cadena produce el texto "null", lo que te lleva de vuelta a la inicialización. La descripción debería informar del estado actual, por lo que imprimir el objeto dos veces no debería hacer avanzar un reloj ni celebrar un cumpleaños.
Puntos clave
- Escribe public String toString() sin parámetros y devuelve texto legible.
- La anotación @Override permite al compilador comprobar que el método sustituye uno existente.
- Imprimir un objeto y unirlo a una cadena utilizan toString automáticamente.
- Mantén toString libre de cambios de estado y deja que quien lo llama decida adónde va el texto.
- String.format puede rellenar valores y utilizar una configuración regional explícita para producir una salida predecible.
5.2 De un requisito a una clase probada
Empieza por lo que debe recordar un objeto, lo que quienes lo utilizan pueden pedirle que haga y qué estados deben permitirse. Después convierte cada parte en campos, constructores y métodos.
Extrae el diseño de una descripción
«Un libro de biblioteca tiene un título, un autor y un número de páginas. Se puede prestar y devolver. No se puede volver a prestar mientras ya esté prestado».
Utiliza LibraryBook como nombre de la clase. Almacena los tres valores descriptivos y un estado de préstamo booleano. El título, el autor y el número de páginas permanecen fijos, así que hazlos final. El estado de préstamo cambia mediante acciones con una función clara. No es necesario un método modificador para cada campo.
Construye la clase completa
public class LibraryBook {
private final String title;
private final String author;
private final int pages;
private boolean lentOut;
public LibraryBook(String title, String author, int pages) {
this.title = title;
this.author = author;
this.pages = pages;
this.lentOut = false;
}
public boolean isLentOut() {
return this.lentOut;
}
public boolean lend() {
if (this.lentOut) {
return false;
}
this.lentOut = true;
return true;
}
public void giveBack() {
this.lentOut = false;
}
@Override
public String toString() {
String status = this.lentOut ? "lent out" : "available";
return this.title + " by " + this.author + ", "
+ this.pages + " pages, " + status;
}
}
El constructor establece que el libro está disponible. lend() comprueba el estado existente antes de cambiarlo; devolver false en un segundo préstamo mantiene la regla. giveBack() hace que el libro esté disponible. El método de acceso informa del estado y toString() describe todo el libro sin modificarlo.
Escribe los resultados esperados antes de ejecutar las llamadas
En el método main clásico de una clase Main independiente:
LibraryBook b = new LibraryBook("Night Train", "A. Rivera", 320);
System.out.println(b); // Night Train by A. Rivera, 320 pages, available
System.out.println(b.lend()); // true
System.out.println(b.lend()); // false
b.giveBack();
System.out.println(b.lend()); // true
El segundo intento de préstamo es esencial: un método que siempre active el indicador y devuelva true superaría la primera llamada, pero fallaría esta comprobación. Prueba el estado y los valores de retorno con isLentOut(). Prueba también un segundo libro para comprobar que un préstamo de un libro deja disponible al otro.
Prueba los puntos donde cambia el comportamiento
Cubre todos los constructores y métodos públicos. Para las comprobaciones de rango, prueba ambos extremos y valores justo fuera de ellos. Para un reloj, comprueba el cambio de minuto y el paso a medianoche. Para un método modificador que rechaza o ignora valores, comprueba que la entrada no válida tiene el efecto previsto sobre el estado anterior. Escribe primero el resultado esperado para que una salida inesperada no se convierta silenciosamente en tu nueva expectativa.
Construye en pequeños incrementos: primero los campos y el constructor, después una descripción legible y luego una operación y sus comprobaciones cada vez. Guarda las clases públicas habituales en los archivos correspondientes, compílalas juntas y ejecuta la clase que contiene main. Mantener las operaciones del modelo separadas de la salida en pantalla permite que la misma clase sirva para distintos programas.
Puntos clave
- Convierte los datos que se recuerdan en campos privados y las acciones permitidas en métodos.
- Escribe las reglas del estado antes de implementar constructores y cambios.
- Utiliza final para valores fijos de cada objeto y evita métodos modificadores innecesarios.
- Prueba los valores de retorno y el estado resultante, incluidas llamadas repetidas y objetos separados.
- Comprueba los valores límite y las entradas no válidas, además de los valores habituales.
- Construye y prueba una parte útil cada vez.
- Mantén el comportamiento del modelo separado del programa principal que imprime los resultados.
Ejemplos de Clases y objetos en Java
1De una clase a dos mascotas
10 pasos
- 1IntroducciónUn tipo para las cosas de tu programa
Un programa de mascotas necesita recordar juntos un nombre, una especie y una edad. Una clase da un tipo a ese grupo y ofrece métodos que lo utilizan. Cada objeto es una mascota creada a partir de esa definición.
Sigue la diferencia entre la definición y las mascotas que produce. Después sigue el estado de dos objetos de mascotas y observa por qué una variable adicional no siempre significa un objeto adicional.
- 2AnalogíaUn plano y sus instancias
Piensa en una clase como el plano de una construcción y en sus objetos como las casas construidas a partir de él. El plano describe lo que contiene cada casa, pero no es una casa en sí.
Una definición de
Petpuede describir muchas mascotas. Cada una tiene campos para los mismos tipos de datos, pero una puede ser una gata de tres años y otra un perro de cinco años. Definir los campos crea el plano; la creación de objetos proporciona instancias reales. - 3EjemploIdentifica el estado y el comportamiento
Los campos
name,speciesyagede una mascota almacenan su estado. Para Luna, sus valores son"Luna","cat"y3.El método
celebrateBirthday()proporciona comportamiento. Su cuerpo puede ejecutarthis.age++;, cambiando la edad de la mascota receptora. El método forma parte de la definición de la clase; el valor que cambia pertenece a una mascota concreta. - 4Desafío¿Una definición crea una mascota?
Un programador escribe una clase
Petcon tres campos y un método de cumpleaños. No se ha ejecutado ninguna expresión de creación de objetos. ¿Cuántos objetos de mascotas ha creado esa definición?---reveal---
Ninguno. La clase define un tipo y su estado y comportamiento disponibles. Los objetos aparecen cuando el programa los crea, por ejemplo con
new Pet(...). Tres declaraciones de campos describen tres datos por mascota, no tres mascotas. - 5EjemploCrea el primer objeto
Lee
Pet luna = new Pet("Luna", "cat", 3);por partes.Pet lunadeclara una variable.new Pet(...)crea una mascota y ejecuta el constructor con los tres argumentos proporcionados.El constructor almacena los valores iniciales. La referencia producida por
newse asigna aluna, lo que da al código posterior una forma de acceder a este objeto. DeclararPet luna;por sí solo no proporcionaría ningún objeto sobre el que llamar a un método. - 6ExplicaciónLlama a un método sobre su receptor
En
luna.celebrateBirthday(), la expresión anterior al punto identifica el objeto receptor. El método de cumpleaños se ejecuta para Luna y aumenta su edad de 3 a 4.int age = luna.getAge();recupera después la edad actual para utilizarla en otro lugar.Pet.celebrateBirthday()no puede elegir una mascota: es un método de instancia y un nombre de clase no proporciona ningún objeto concreto. - 7EjemploCrea una segunda mascota
Ahora ejecuta
Pet max = new Pet("Max", "dog", 5);. Una segunda expresiónnewcrea un segundo objeto con sus propios campos.Después de otra llamada a
luna.celebrateBirthday(), Luna tiene 5 años y Max sigue teniendo 5. Que tengan la misma edad no hace que sean el mismo objeto. Un cumpleaños posterior de Luna solo cambia la edad de Luna porque la edad de Max se guarda en los campos de otro objeto. - 8Idea claveUna asignación puede compartir un objeto
Pet other = luna;copia la referencia de Luna. No llama a un constructor ni copia sus campos en otra mascota.Los nombres
otherylunaacceden ahora al mismo objeto. Llamar aother.celebrateBirthday()cambia la edad de esa mascota de 5 a 6, yluna.getAge()también ve 6. Cuenta las creaciones de objetos por separado de las declaraciones de variables. - 9DesafíoSigue una referencia compartida y una mascota independiente
Dos mascotas distintas empiezan con edades de 1 para
ay 8 parab. El código ejecutaPet c = a; c.celebrateBirthday(); b.celebrateBirthday();. ¿Qué edades indicanayb?---reveal---
Indican 2 y 9.
ccomparte el objeto dea, por lo que su llamada aumenta la edad de esa mascota. La llamada mediantebaumenta la de la mascota independiente. La clase proporciona el mismo comportamiento de cumpleaños a ambas, pero cada llamada tiene su propio receptor. - 10RepasoLee con atención la creación y las llamadas
Distingue tres funciones: la clase define el tipo, cada objeto almacena su propio estado de instancia y una variable de referencia permite acceder a un objeto.
Al leer código, marca cada
new, haz coincidir sus argumentos con el constructor e identifica el receptor antes de seguir una llamada a un método. Una simple asignación de referencia añade una vía de acceso a un objeto existente. Un segundonewcrea un objeto independiente con su propio estado.
2Construye correctamente el estado inicial
14 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDa datos útiles a cada objeto nuevo
- 2ExplicaciónElige el estado duradero
- 3ExplicaciónDistingue los valores predeterminados de los valores útiles
- 4DesafíoElige un campo o una variable local
- 5ExplicaciónLee la cabecera del constructor
- 6EjemploTransfiere los parámetros a los campos
- 7ConsejoUna asignación válida que no almacena nada
- 8DesafíoIdentifica el campo que no cambia
- 9ConexiónCrea también los objetos internos
- 10EjemploOfrece una vía predeterminada útil
- 11ExplicaciónSigue un objeto a través de la cadena
- 12DesafíoDiagnostica una expresión new engañosa
- 13DesafíoCombina un campo fijo con una sobrecarga
- 14RepasoComprueba cada vía hasta un objeto terminado
3Sigue los cambios de estado y el estado compartido
13 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónSigue lo que cambia cada llamada
- 2ExplicaciónDevuelve un valor a quien llama al método
- 3EjemploEscala las dimensiones almacenadas
- 4DesafíoComprueba el resultado devuelto después de un cambio
- 5EjemploAvanza hasta pasar la medianoche
- 6ConsejoCorrige un reinicio que no cambia el estado
- 7Idea claveTen en cuenta cada retorno normal
- 8ExplicaciónDistingue dos cuentas de un contador compartido
- 9EjemploProporciona un objeto en código estático
- 10ConexiónReconoce una constante
- 11DesafíoSigue los dos tipos de estado
- 12DesafíoDescubre por qué objetos distintos cambian juntos
- 13RepasoRelaciona cada operación con su propietario
4Protege cada vía de cambio del estado
14 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónHaz que la clase sea responsable de sus reglas
- 2ExplicaciónOculta el campo tras una operación
- 3ConsejoElige el acceso útil más restringido
- 4DesafíoDetermina dónde funciona el acceso privado
- 5EjemploDevuelve información con un método de acceso
- 6ConexiónOfrece acciones adecuadas para el objeto
- 7DesafíoLee sin permitir la sustitución
- 8ExplicaciónElige una política para entradas no válidas
- 9EjemploSigue la limitación en el límite superior
- 10EjemploComprueba el primer estado
- 11DesafíoSigue la opción de ignorar en lugar de limitar
- 12Idea claveUna lista privada todavía puede quedar expuesta
- 13DesafíoCierra ambas vías sin comprobaciones
- 14RepasoRevisa la interfaz pública
5Construye y prueba una clase útil
12 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónConvierte un requisito en comportamiento visible
- 2ExplicaciónUtiliza la cabecera exacta de la descripción
- 3EjemploDevuelve el estado actual como texto
- 4ConsejoDa formato a un reloj sin cambiarlo
- 5DesafíoCorrige la impresión automática
- 6EjemploElige los campos a partir del requisito
- 7EjemploEstablece el estado inicial
- 8EjemploImplementa la regla antes del cambio
- 9DesafíoPredice una secuencia antes de ejecutarla
- 10ConexiónPrueba los casos que una ejecución sencilla pasa por alto
- 11DesafíoDistingue informar de modificar
- 12RepasoConstruye con una garantía pública comprobable
Ejercicios de Clases y objetos en Java
Set 1: Comprueba la inicialización y los cambios controlados10 Preguntas de Práctica
Pregunta 1 de 10
Locker tiene un campo occupied y un método release(). ¿Qué parte de esta clase describe un comportamiento?Mostrar respuestaOcultar respuesta
release() describe algo que puede hacer una taquilla. El valor actual de occupied pertenece a su estado. Cambiar el estado puede ser el efecto de un comportamiento, pero el indicador almacenado es un dato, no una operación.Pregunta 2 de 10
Panel almacena la anchura y la altura. Su anchura puede cambiar y getArea() siempre debe indicar el área actual. ¿Cómo debería representarse el área?Mostrar respuestaOcultar respuesta
Pregunta 3 de 10
public Sensor(int channel). Quien la utiliza llama a new Sensor(). ¿Por qué no compila?Mostrar respuestaOcultar respuesta
Sensor(int channel) hace que Java deje de proporcionar un constructor predeterminado. Quien llama al constructor debe proporcionar un argumento compatible o la clase debe ofrecer explícitamente una sobrecarga sin argumentos que resulte útil. Java no completa el valor con 0 solo porque un campo entero tendría ese valor predeterminado.Pregunta 4 de 10
private int reading = 9;. Su método es public void reset() { int reading = 0; }. ¿Qué indica un método de acceso que devuelve this.reading después de reset()?Mostrar respuestaOcultar respuesta
reset() crea una variable local y le asigna 0. Nunca escribe en el campo, por lo que el método de acceso sigue indicando 9. Eliminar el tipo y asignar this.reading = 0; reiniciaría el estado duradero del objeto.Pregunta 5 de 10
Mostrar respuestaOcultar respuesta
Pregunta 6 de 10
minutesSinceMidnight, mientras sus métodos de acceso siguen devolviendo los mismos valores. ¿Por qué quienes lo utilizan pueden conservar sus llamadas a esos métodos?Mostrar respuestaOcultar respuesta
Pregunta 7 de 10
setValue(25) y luego setValue(8), ¿cuáles son los valores almacenados tras cada llamada?Mostrar respuestaOcultar respuesta
Pregunta 8 de 10
Group debe contener como máximo cuatro nombres. addName aplica el límite, pero Group(ArrayList<String> names) almacena directamente la lista proporcionada y getNames() devuelve la lista interna. ¿Qué diseño mantiene el límite frente a cambios realizados por quienes utilizan la clase?Mostrar respuestaOcultar respuesta
addName, mientras que copiar solo la entrada deja abierta la vía del método de acceso.Pregunta 9 de 10
toString() sin argumentos?Mostrar respuestaOcultar respuesta
toString() sin argumentos con el tipo de retorno incompatible void.Pregunta 10 de 10
use() devuelve false si ya se ha usado; de lo contrario, activa el indicador y devuelve true. reset() desactiva el indicador. toString() solo informa de él. ¿Qué devuelven las llamadas a use en use(); println(pass); use(); reset(); use(); use();?Mostrar respuestaOcultar respuesta
Set 2: Crea objetos y lee su estado10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
Parcel para crear varios paquetes. ¿Cómo se llama un paquete creado mientras se ejecuta el programa?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
Bell se almacena en bell, y ring() es un método de instancia. ¿Cómo debería el programa hacer sonar esa campana?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
private int attempts; sin inicializador ni asignación en el constructor. ¿Qué valor almacena un objeto nuevo en este campo?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
new Badge("Visitor"), getText() devuelve null. El campo es private String text;, el método de acceso lo devuelve y el cuerpo del constructor es text = text;. ¿Cómo debería el constructor almacenar su parámetro text?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Ticket() { this(4); } y Ticket(int zones) { this.zones = zones + 1; }. ¿Qué valor almacena new Ticket() en zones?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
MinuteClock almacena horas de 0 a 23 y minutos de 0 a 59. advance() añade un minuto y gestiona el cambio de hora y el paso a medianoche. isMidnight() comprueba si son las 00:00. A partir de las 23:57, ejecuta advance(); advance(); advance(); if (isMidnight()) { advance(); } advance();. ¿Cuál es la hora final?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
Lamp debe recordar su propio estado de encendido o apagado. ¿Cómo debería declararse ese estado?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Bin se escribe como int capacity; sin modificador de acceso. ¿Qué acceso tiene?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Session tiene private boolean active;. Quienes la utilizan necesitan comprobarlo, pero solo pueden cambiarlo mediante start() y stop(). ¿Qué método de acceso se ajusta a este diseño?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
public String toString() { return "Ready"; }. ¿Qué texto produce System.out.println("State: " + object);?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 3: Sigue el estado de los objetos en secuencias más largas10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
Marker tiene un nombre y setName. Ejecuta Marker a = new Marker("One"); Marker b = a; a = new Marker("Two"); b.setName("Three");. ¿Qué devuelven a.getName() y b.getName()?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
private int level = 6;. Su constructor es public Beacon(int level) { this.level = level + 2; }. ¿Qué almacena new Beacon(3)?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
public Tag(String text). ¿Qué constructor adicional proporciona una sobrecarga distinta?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
scale(k) multiplica ambas dimensiones por k; area() devuelve su producto. Ejecuta scale(2); double saved = area(); scale(0.5);. ¿Cuáles son saved y el resultado final de area()?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Dial recién iniciada tiene el campo de instancia value y el campo estático created, ambos inicialmente en 0. Cada constructor incrementa created una vez; turn() solo incrementa el valor de su receptor. Ejecuta Dial a = new Dial(); Dial b = a; b.turn(); b = new Dial(); b.turn(); b.turn();. ¿Cuáles son los valores de a.value, b.value y created?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
private String label;. ¿Qué implementación proporciona ese valor a quien lo llama?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
setLevel limita un nivel al rango de 0 a 10, incluidos ambos extremos. El constructor llama a ese método modificador y raise() llama a setLevel(this.level + 1). Partiendo de new Level(13), ejecuta raise(); setLevel(-2); raise(); raise();. ¿Cuál es el nivel final?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
String.format(java.util.Locale.US, "%02d:%02d", 4, 7)?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Seat debe rechazar una segunda reserva hasta que se cancele la anterior. Una prueba solo comprueba actualmente la primera llamada correcta a reserve(). ¿Qué llamada posterior comprueba mejor la regla de rechazo?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 4: Diagnostica diseños y combina las reglas10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
Pump?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
Token tiene un valor numérico y addOne() lo incrementa. Ejecuta Token a = new Token(2); Token b = a; b.addOne(); Token c = new Token(7); a = c; a.addOne(); b.addOne();. ¿Qué valores indican a, b y c?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
add(int amount) declara actualmente int total = amount; dentro del método. ¿Qué cambio de almacenamiento permite acumular valores?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
Un Bucket declara private int capacity = 2; y una lista de instancia vacía items. Su constructor es Bucket(int capacity) { capacity = capacity; }. add devuelve false sin añadir nada cuando el tamaño de la lista es al menos la capacidad almacenada; de lo contrario, añade el elemento y devuelve true. snapshot() devuelve new ArrayList<>(this.items).
Ejecuta Bucket b = new Bucket(4); b.add("A"); ArrayList<String> view = b.snapshot(); view.add("B");. Después llama a b.add("C") y b.add("D"). ¿Qué devuelven estas dos últimas llamadas y cuántos elementos contiene finalmente b?
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Route tiene el campo final code y el campo estático created, inicialmente en 0. Sus constructores son Route() { this("local"); created++; } y Route(String code) { this.code = code; created++; }. Después de una llamada a cada constructor, created debería contar dos objetos. ¿Qué corrección da el recuento correcto?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
advance() añade un minuto y gestiona el cambio al completar 24 horas. getHour() lee la hora actual. Ejecuta int h = getHour(); advance(); if (getHour() != h) { advance(); } advance();. ¿Cuáles son h y la hora final?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
scale. Su método de acceso devuelve this.width * this.height y no hay ningún campo de área. ¿Por qué es válido este diseño del método de acceso?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Album tiene un límite de tres leyendas. Su constructor rechaza más de tres leyendas y almacena new ArrayList<>(captions). getCaptions() devuelve otra copia; addCaption rechaza adiciones cuando se alcanza el límite. Una persona proporciona dos leyendas, añade una tercera a la lista original, añade una leyenda al resultado del método de acceso y después llama una vez a addCaption. ¿Cuántas leyendas contiene el Album?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Door debe rechazar open() cuando está bloqueada. Una puerta nueva empieza cerrada y desbloqueada. lock() solo tiene éxito mientras está cerrada; unlock() quita el bloqueo. ¿Qué secuencia de prueba comprueba el rechazo mientras está bloqueada y después una apertura correcta tras desbloquearla?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
¿Te atascas con una pregunta tuya? Ayuda con Tareas
Términos Clave
A
Acceso de paquete
int count; permite que otra clase del mismo paquete sin nombre lea o cambie el campo.Anotación @Override
@Override pide al compilador que verifique que una declaración de método sustituye un método ya proporcionado por un supertipo.@Override encima de tostring() revela el error de mayúsculas en lugar de dejar la impresión automática sin cambios.Argumento
new Clock(9, 5), los argumentos 9 y 5 proporcionan la hora y el minuto del nuevo reloj.Á
Ámbito (alcance)
if termina en ese bloque, por lo que el código posterior no puede utilizar su nombre.C
Campo estático
created puede aumentar cada vez que el constructor inicializa una nueva instancia de la clase.Campo final
Clase
Pet reúne un nombre, una especie y una edad con operaciones como celebrateBirthday().Comportamiento
lend() y giveBack() para que quienes lo utilizan puedan gestionar su estado de préstamo.Constante
static final, a menudo público y con nombre en UPPER_SNAKE_CASE.MAX_CELSIUS proporciona el mismo límite superior de temperatura a la clase y a quienes la utilizan.Constructor
Pet copia el nombre, la especie y la edad proporcionados en los campos de la nueva mascota.Constructor predeterminado
new Pet() necesita una sobrecarga explícita.Constructor sin argumentos
Clock() puede delegar con this(0, 0) para iniciar el reloj a medianoche.Contexto estático
pet.getAge() proporciona en cambio un objeto concreto.Copia defensiva
new ArrayList<>(this.tracks) evita que los cambios externos de la lista afecten a la lista interna.D
Desarrollo incremental
Diseño de clases
E
Encadenamiento de constructores
this(...).this(name, species, 0) para reutilizar la inicialización con una edad predeterminada.Encapsulación (encapsulamiento)
Pet combina un campo de edad privado con métodos de comprobación que rechazan cambios no válidos.Estado
Excepción IllegalArgumentException
IllegalArgumentException es una excepción que un método o constructor puede lanzar para rechazar un argumento que incumple sus reglas de entrada.IllegalArgumentException ante una capacidad negativa impide que la construcción devuelva un objeto no válido.I
Inicialización
new ArrayList<>() para que después se puedan añadir entradas.Instancia
Pet cuando se crean por separado.Interfaz pública
lend(), giveBack() e isLentOut() mientras su indicador de préstamo permanece privado.Invariante
Invocación recursiva de constructores
Box() y Box(int) delegan el uno en el otro.L
Limitación al rango permitido (clamping)
M
Método de acceso (getter)
get.getArea() puede calcular la anchura por la altura aunque la clase no almacene un campo de área separado.Método de acción
lend() comprueba el estado actual de préstamo, rechaza un préstamo repetido e indica si el préstamo tuvo éxito.Método de instancia
scale es un método de instancia: a.scale(2) cambia el rectángulo a, mientras que otro rectángulo permanece sin cambios.Método estático
main puede crear Counter c y después llamar a c.increment() mediante esa referencia.Método modificador (setter)
setAge(int age) puede ignorar entradas negativas para que la edad almacenada permanezca en su rango permitido.Método String.format
String.format construye texto a partir de una cadena de formato y valores, y permite establecer anchuras fijas y posiciones decimales.String.format con java.util.Locale.US y "%.2f" da formato a 7,5 como "7.50" independientemente de la configuración regional predeterminada.Método toString
toString() devuelve la representación textual de un objeto, lo que permite mostrar detalles legibles al imprimir y concatenar cadenas.toString de un reloj devuelve "09:05", por lo que imprimir el reloj muestra una hora útil en lugar del texto de clase y hash.Modificador de acceso
private, protected o public que controla el acceso a una declaración.private mantiene un método auxiliar disponible dentro de su clase sin exponerlo a otras clases.Modificador private
private restringe el acceso a un miembro al código dentro de su clase, de modo que el código independiente de nivel superior debe usar la interfaz pública.pet.age = -1; falle en una clase Main independiente y exige una llamada a un método controlado.Modificador protected
protected permite el acceso desde el mismo paquete y un acceso restringido desde código de subclases fuera de ese paquete.Modificador public
public permite acceder a un miembro dondequiera que sea accesible el tipo que lo declara, para que quienes lo utilizan puedan llamar a la operación expuesta.lend() permite que Main solicite un préstamo mientras el campo de estado privado del libro permanece oculto.N
Notación de punto
luna.getAge() indica a Java que la mascota a la que se accede mediante luna debe proporcionar su edad.null
null significa que una referencia no tiene ningún objeto al que acceder; los campos de tipos de clase lo reciben salvo que se inicialicen de otra forma.add sobre un campo de lista que sigue en null falla porque no se creó ningún objeto de lista.O
Objeto
new separadas pueden tener edades distintas y seguir una misma definición de clase.Objeto receptor
book.lend(), el receptor es el libro al que se accede mediante book, cuyo indicador de préstamo comprueba el método.Ocultación de información
getHours() coherente para quienes ya lo utilizan.Ocultación de nombres (shadowing)
this.age = age;: el lado izquierdo es el campo y el derecho es la entrada.P
Palabra clave new
new inicia una expresión de creación de objetos que ejecuta un constructor y produce una referencia al objeto.new Pet("Luna", "cat", 3) crea una mascota y proporciona tres argumentos para su estado inicial.Palabra clave this
this hace referencia al objeto actual dentro del código de instancia y distingue sus campos de parámetros con el mismo nombre.this.name = name; escribe la nueva entrada en el campo de esa mascota concreta.Parámetro
age de un constructor de mascotas recibe 3 cuando la llamada proporciona 3 en esa posición.Propiedad de solo lectura
getTitle() pero ninguna operación para sustituir el título.Prueba de valores límite
R
Referencia
Pet other = luna;, las dos variables contienen referencias a la misma mascota, por lo que cualquiera de ellas puede acceder a ella.Resultado esperado
lend() sobre un libro prestado es false, con el indicador de préstamo sin cambios.S
Seguimiento del estado
Sobrecarga de constructores
T
Tiempo de vida
V
Validación
Valor de retorno
r.area() puede duplicarse en una expresión; imprimir el área por sí solo no proporciona ningún valor.Valor predeterminado
false; a una variable booleana local se le debe asignar un valor antes de poder leerla.Variable de instancia
age de cada mascota conserva su propio valor, aunque la declaración aparece una sola vez en Pet.Variable local
total dentro de un método de cálculo guarda trabajo temporal que el objeto no necesita recordar.void
void declara que un método no proporciona ningún valor de retorno, aunque cambie el estado o imprima una salida.void porque su función es aumentar la edad almacenada de su receptor.- 1Primeros programas en Java
- 2Condiciones y bucles en Java
- 3Métodos en Java
- 4Listas, arreglos y cadenas en Java
- 5Clases y objetos en Java
- 6Objetos y referencias en Java
- 7HashMap y colecciones en Java
- 8Herencia, interfaces y polimorfismo en Java
- 9Excepciones y archivos en Java
- 10Paquetes en Java
- 11Genéricos y expresiones lambda en Java
Sobre esta unidad
Crea tus propios Materiales de Estudio
Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.