5.10 Anexos
1. Wrappers (envoltorios)¶
Los wrappers permiten "envolver" datos primitivos en objetos, también se llaman clases contenedoras. La diferencia entre un tipo primitivo y un wrapper es que este último es una clase y por tanto, cuando trabajamos con wrappers estamos trabajando con objetos.
Atención al paso de parámetros de tipo Wrapper
Como son objetos debemos tener cuidado en el paso como parámetro en métodos ya que en el wrapper se realiza por referencia.
Una de las principales ventajas del uso de wrappers son la facilidad de conversión entre tipos primitivos y cadenas.
Hay una clase contenedora por cada uno de los tipos primitivos de Java. Los datos primitivos se escriben en minúsculas y los wrappers se escriben con la primera letra en mayúsculas.
| Tipo primitivo | Wrapper asociado |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Char |
| boolean | Boolean |
Cada clase wrapper tiene dos constructores, uno se le pasa por parámetro el dato de tipo primitivo y otro se le pasa un String.
Para wrapper Integer:
Antiguamente, una vez asignado un valor a un objeto o wrapper Integer, este no podía cambiarse. Actualmente e internamente se puede realizar un apoyo en variables y wrapers internos para poder variar el valor de un wrapper.
Los wrapper disponen de una serie de métodos que permiten realizar funciones de conversión de datos. Por ejemplo, el wrapper Integer dispone de los siguientes métodos:
| Método | Descripción |
|---|---|
Integer(int)Integer(String) |
Constructores |
byteValue()shortValue()intValue()longValue()doubleValue()floatValue() |
Funciones de conversión con datos primitivos |
Integer decode(String)Integer parseInt(String)Integer parseInt(String, int)Integer valueOf(String)String toString() |
Conversión a String |
String toBinaryString(int)String toHexString(int)String toOctalString(int) |
Conversión a otros sistemas de numeración |
MAX_VALUE, MIN_VALU, TYPE |
Constantes |
1.1. Métodos valueOf()¶
El método valueOf() permite crear objetos wrapper y se le pasa un parámetro String y opcionalmente otro parámetro que indica la base en la que será representado el primer parámetro.
1.2. Métodos xxxValue()¶
Los métodos xxxValue() permiten convertir un wrapper en un dato de tipo primitivo y no necesitan argumentos.
1.3. Métodos parseXxxx()¶
Los métodos parseXxxx() permiten convertir un wrapper en un dato de tipo primitivo y le pasamos como parámetro el String con el valor que deseamos convertir y opcionalmente la base a la que convertiremos el valor (2, 8, 10 o 16).
1.4. Métodos toString()¶
El método toString() permite retornar un String con el valor primitivo que se encuentra en el objeto contenedor. Se le pasa un parámetro que es el wrapper y opcionalmente para Integer y Long un parámetro con la base a la que convertiremos el valor (2, 8, 10 o 16).
1.5. Métodos toXxxxxString() (Binario, Hexadecimal y Octal)¶
Los métodos toXxxxxString() permiten a las clases contenedoras Integer y Long convertir números en base 10 a otras bases, retornando un String con el valor primitivo que se encuentra en el objeto contenedor.
Para resumir, los métodos esenciales para las conversiones son:
-
primitive xxxValue()– Para convertir de Wrapper a primitive -
primitive parseXxx(String)– Para convertir un String en primitive Wrapper valueOf(String)– Para convertir String en Wrapper
Ejemplo completo Anexo1Wrappers
2. Clase Date¶
La clase Date es una utilidad contenida en el paquete java.util y permiten trabajar con fechas y horas. La fecha y hora se almacenan en un entero de tipo Long que almacena los milisegundos transcurridos desde el 1 de Enero de de 1970 que se obtienen con getTime(). Importamos java.util.Date.
2.1. Clase GregorianCalendar¶
Para utilizar fechas y horas se utiliza la clase GregorianCalendar que dispone de variables enteras como: DAY_OF_WEEK, DAY_OF_MONTH, YEAR, MONTH, HOUR, MINUTE, SECOND, MILLISECOND, WEEK_OF_MONTH, WEEK_OF_YEAR, … (importamos clase java.util.Calendar y java.util.GregorianCalendar)
2.2. Paquete java.time¶
El paquete java.time dispone de las clases LocalDate, LocalTime, LocalDateTime, Duration y Period para trabajar con fechas y horas.
Estas clases no tienen constructores públicos, y por tanto, no se puede usar new para crear objetos de estas clases. Necesitas usar sus métodos static para instanciarlas.
No es válido llamar directamente al constructor usando new, ya que no tienen un constructor público.
Ejemplo ERRÓNEO:
LocalDate¶
LocalDate representa una fecha determinada. Haciendo uso del método of(), esta clase puede crear un LocalDate teniendo en cuenta el año, mes y día. Finalmente, para capturar el LocalDate actual se puede usar el método now():
LocalTime¶
LocalTime, representa un tiempo determinado. Haciendo uso del método of(), esta clase puede crear un LocalTime teniendo en cuenta la hora, minuto, segundo y nanosegundo. Finalmente, para capturar el LocalTime actual se puede usar el método now().
LocalDateTime¶
LocalDateTime, es una clase compuesta, la cual combina las clases anteriormente mencionadas LocalDate y LocalTime. Podemos construir un LocalDateTime haciendo uso de todos los campos (año, mes, día, hora, minuto, segundo, nanosegundo).
También, se puede crear un objeto LocalDateTime basado en los tipos LocalDate y LocalTime, haciendo uso del método of() (LocalDate date, LocalTime time):
Duration¶
Duration, hace referencia a la diferencia que existe entre dos objetos de tiempo. La duración denota la cantidad de tiempo en horas, minutos y segundos.
También, se puede crear Duration basado en los métodos ofDays(long days), ofHours(long hours), ofMilis(long milis), ofMinutes(long minutes), ofNanos(long nanos), ofSeconds(long seconds).
Period¶
Period, hace referencia a la diferencia que existe entre dos fechas. Esta clase denota la cantidad de tiempo en años, meses y días.
Se puede crear Period basado en el método of(int years, int months, int days). En el siguiente ejemplo, se crea un período de 1 año 2 meses y 3 días:
Se puede crear Period basado en los métodos ofDays(int days), ofMonths(int months), ofWeeks(int weeks), ofYears(int years).
2.3. ChronoUnit¶
Permite devolver el tiempo transcurrido entre dos fechas en diferentes formatos (DAYS, MONTHS, YEARS, HOURS, MINUTES, SECONDS, ...). Debemos importar la clase time.temporal.ChronoUnit;
2.4. Introducir fecha como Cadena¶
Podemos introducir la fecha como una cadena con el formato que deseemos y posteriormente convertir a fecha con la sentencia parse. Debemos importar las clases time y time.format.
Ojo
A partir de Java 8yes para el año de la era (BC AD), y para el año debemos usar u.
Más detalles sobre los formatos: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
2.5. Manipulación¶
- Manipulando
LocalDate
Haciendo uso de los métodos withYear(int year), withMonth(int month), withDayOfMonth(int dayOfMonth), with(TemporalField field, long newValue) se puede modificar el LocalDate.
- Manipulando
LocalTime
Haciendo uso de los métodos withHour(int hour), withMinute(int minute), withSecond(int second), withNano(int nanoOfSecond) se puede modificar el LocalTime.
- Manipulando
LocalDateTime
LocalDateTime provee los mismo métodos mencionados en las clases LocalDate y LocalTime.
2.6. Operaciones¶
- Operaciones con
LocalDate
Realizar operaciones como suma o resta de días, meses, años, etc es muy fácil con la nueva Date API. Los siguientes métodos plus(long amountToAdd, TemporalUnit unit), minus(long amountToSubtract, TemporalUnit unit) proveen una manera general de realizar estas operaciones. (Debemos importar la clase java.time.temporal.ChronoUnit para poder utilizar las unidades: ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS).
También se puede hacer cálculos basados en un Period. En el siguiente ejemplo, se crea un Period de 1 día para poder realizar los cálculos.
Finalmente, haciendo uso de métodos explícitos como plusDays(long daysToAdd) y minusDays(long daysToSubtract) se puede indicar el valor a incrementar o reducir.
- Operaciones con
LocalTime
La nueva Date API perimite realizar operaciones como suma y resta de horas, minutos, segundos, etc. Al igual que LocalDate, los siguientes métodos plus(long amountToAdd, TemporalUnit unit), minus(long amountToSubtract, TemporalUnit unit) proveen una manera general de realizar estas operaciones.
(Debemos importar la clase java.time.temporal.ChronoUnit para poder utilizar las unidades: ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS, ChronoUnit.NANOS).
También se puede hacer cálculos basados en un Duration. En el siguiente ejemplo, se crea un Duration de 1 hora para poder realizar los cálculos.
Finalmente, haciendo uso de métodos explícitos como plusHours(long hoursToAdd) y minusHours(long hoursToSubtract) se puede indicar el valor a incrementar o reducir.
- Operaciones con
LocalDateTime
LocalDateTime, al ser una clase compuesta por LocalDate y LocalTime ofrece los mismos métodos para realizar operaciones.
(Debemos importar la clase java.time.temporal.ChronoUnit para poder utilizar las unidades: ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS, ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS, ChronoUnit.NANOS).
En el siguiente ejemplo, se hace uso de Period y Duration:
Finalmente, haciendo uso de los métodos plusX(long xToAdd) o minusX(long xToSubtract):
Además, métodos como isBefore, isAfter, isEequal están disponibles para comparar las siguientes clases LocalDate, LocalTime y LocalDateTime.
2.7. Formatos¶
Cuando se trabaja con fechas, en ocasiones se requiere de un formato personalizado. Podemos usar el método ofPattern(String pattern), para definir un formato en particular.
Para utilizar DateTimeFormatter.ofPattern debemos importar la clase con import java.time.format.DateTimeFormatter;
El patrón del formato se realiza en función a la siguiente tabla de símbolos:
| Símbolo | Descripción | Salida |
|---|---|---|
| y | Año | 2004; 04 |
| D | Día del Año | 189 |
| M | Mes del Año | 7; 07; Jul; July; J |
| d | Día del Mes | 10 |
| w | Semana del Año | 27 |
| E | Día de la Semana | Tue; Tuesday; T |
| F | Semana del Mes | 3 |
| a | AM/PM | PM |
| K | Hora AM/PM (0-11) | 0 |
| H | Hora del día (0-23) | 0 |
| m | Minutos de la hora | 30 |
| s | Segundos del minuto | 55 |
| n | Nanosegundos del Segundo | 987654321 |
| '' | Texto | 'Día de la semana' |
Día de la Semana¶
La función getDayOfWeek() devuelve un elemento del tipo DayOfWeek que corresponde el día de la semana de una fecha. Debemos importar la clase java.time.DayOfWeek.
Por ejemplo, el lunes será DayOfWeek.MONDAY.
Ejemplo completo Anexo2Date
3. Conversión entre objetos (Casting)¶
La esencia de Casting permite convertir un dato de tipo primitivo en otro generalmente de más precisión.
Entre objetos es posible realizar el casting.
En el siguiente ejemplo tenemos una clase persona con una subclase empleado y este a su vez una subclase encargado.
Si creamos una instancia de tipo persona y le asignamos un objeto de tipo empleado o encargado, al ser una subclase no existe ningún tipo de problema, ya que todo encargado o empleado es persona.
Por otro lado, si intentamos asignar valores a los atributos específicos de empleado o encargado nos encontramos con una pérdida de precisión puesto que no se pueden ejecutar todos los métodos de los que dispone un objeto de tipo empleado o encargado, ya que persona contiene menos métodos que la clase empleado o encargado. En este caso es necesario hacer un casting, sino el compilador dará error.
Ejemplo:
Las reglas a la hora de realizar casting es que:
- cuando se utiliza una clase más específica (más abajo en la jerarquía) no hace falta casting. Es lo que llamamos casting implícito.
- cuando se utiliza una clase menos específica (más arriba en la jerarquía) hay que hacer un casting explícito.
¿Porqué a la hora de imprimir el casting implícito la clase más genérica se imprime con el método más especializado?
Debes entender que en realidad encargadoCarniceria es un Encargado que se disfraza de Persona, pero en realidad sus métodos son los especializados (el toString() más moderno sobrescribe al de sus padres. Recuerda que la anotación @override es opcional, y aunque no se indique el método sigue sobrescribiendo al de su padre).
Si por ejemplo usamos este fragmento:
Se imprimirá con el método toString() de la clase Persona (sólo el nombre).
Y si hacemos un casting del objeto David a uno más genérico (Object) seguirá usando el método más especializado:
Ejemplo completo Anexo3Casting
Enlace completo ejemplo Anexo3Casting
Enlace completo ejemplo Persona
Enlace completo ejemplo Empleado
Enlace completo ejemplo Encargado
4. Acceso a métodos de la superclase¶
Para acceder a los métodos de la superclase se utiliza la sentencia super. La sentencia this permite acceder a los campos y métodos de la clase. La sentencia super permite acceder a los campos y métodos de la superclase. El uso de super lo hemos visto en las clases Empleado y Encargado anteriores:
Podemos mostrar el nombre de la clase y el nombre de la clase de la que hereda con getClass() y getSuperclass(). Ejemplo:
5. Clases Anidadas, Clases Internas (Inner Class)¶
Una clase anidada es una clase que es miembro de otra clase. La clase anidada al ser miembro de la clase externa tienen acceso a todos sus métodos y atributos.
Permiten:
- acceder a los campos privados de la otra clase.
- ocultar la clase interna de las otras clases del paquete.
- ...
Para instanciar una clase interna se utilizará la sentencia:
Ejemplo
Observa que ...
Observa que estas clases se definen unas dentro de otras (anidadas o internas), mientras que por ejemplo cuando hemos añadido excepciones a nuestros ejercicios lo hemos hecho como otra clase en el mismo fichero.