0% encontró este documento útil (0 votos)
5 vistas52 páginas

Buenas Prácticas de Programación en Java

Conceptos básicos de Java SE

Cargado por

nicolas Sosa
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
5 vistas52 páginas

Buenas Prácticas de Programación en Java

Conceptos básicos de Java SE

Cargado por

nicolas Sosa
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

Contenido

1. BUENAS PRACTICAS.........................................................................................4

1.1 CamelCase........................................................................................................4

1.2 Convenciones de Nomenclatura en Java..........................................................4

1.3 Evitar la creación innecesaria de objetos, Lazy Initialitation..........................5

1.4 Nunca hacer variables de instancia públicas.................................................5

1.5 Trata siempre de minimizar la Mutabilidad de las clases...............................6

1.6 Trata de usar más las Interfaces sobre las Clases Abstractas......................7

1.7 Limita siempre el alcance de una variable local.............................................7

1.8 Trata de usar librerías estándar en lugar de hacer las tuyas desde cero......7

1.9 Siempre que sea posible trata de usar tipos primitivos en lugar de las clases
Wrapper...................................................................................................................8

1.10 Usa los Strings con mucho cuidado............................................................9

1.11 Siempre regresa colecciones vacías en lugar de nulas..............................9

1.12 El copiado defensivo es salvador...............................................................9

1.13 Nunca dejes salir una excepción de un bloque finally..............................10

1.14 Nunca lances «Exception» directamente..................................................10

1.15 No inicializar una variable String con (‘ ’), si no con (“ ”)...........................10

2. VARIABLES........................................................................................................11

2.1 Tipo de variables.............................................................................................11

2.2 Inferencia de tipos para variables locales (Uso de “var”).................................11

3. CARACTERES ESPECIALES............................................................................13

4. OPERADORES (Todos).....................................................................................13

4.1 Aritméticos.......................................................................................................13

4.2 Relación...........................................................................................................13

4.3 Lógicos............................................................................................................ 14

4.4 Unitarios.......................................................................................................... 15

1
4.5 A nivel de bits.................................................................................................. 15

4.6 Asignación.......................................................................................................16

4.7 Condicional......................................................................................................17

4.8 Jerarquía......................................................................................................... 18

5. USO DE BREACK Y CONTINUE.......................................................................19

5.1 break................................................................................................................19

5.2 continue...........................................................................................................20

5.3 break y continue con etiqueta (Es una mala práctica).................................20

6. PRECEDENCIA DE OPERADORES (PRIORIDAD Y ORDEN DE


EVALUACIÓN)..........................................................................................................21

7. MEMORIA STACK Y HEAP...............................................................................22

8. PROGRAMACIÓN ORIENTADA A OBJETOS (POO).......................................22

8.1 Sobrecarga de constructores...........................................................................22

8.2 Sobrecarga de métodos..................................................................................22

8.3 Modificadores de acceso.............................................................................23

8.4 Miembros estáticos de una clase.................................................................24

8.5 Herencia (extends).......................................................................................25

8.6 Clases y métodos abstractos.......................................................................26

8.7 Interfaces..................................................................................................... 27

8.8 Diferencia entre clase e interfaz...................................................................28

8.9 Polimorfismo................................................................................................ 29

8.10 Upcasting vs Downcasting.............................................................................30

8.11 Uso de la palabra “super”..............................................................................31

8.12 Uso de la palabra “final”.................................................................................32

9. PROGRAMACIÓN EN JAVA..............................................................................33

9.1 Varargs: Argumentos Variables en Java.........................................................33

9.2 Enum: Enumeraciones....................................................................................34

2
9.3 Bloques de inicialización estáticos y no estáticos........................................35

9.4 Autoboxing y Unboxing................................................................................37

9.5 InstanceOf....................................................................................................38

9.6 JavaBeans................................................................................................... 42

9.7 Excepciones (Exception)..............................................................................43

9.8 API de Collections........................................................................................46

9.9 Generics.......................................................................................................50

3
1. BUENAS PRACTICAS

1.1 CamelCase
CamelCase es un estilo de escritura que se aplica a frases o palabras compuestas.
El nombre se debe a que las mayúsculas a lo largo de una palabra en CamelCase
se asemejan a las jorobas de un camello. El nombre CamelCase se podría traducir
como Mayúsculas/Minúsculas Camello.

1.2 Convenciones de Nomenclatura en Java


 Clases e interfaces en Java

Los nombres de las clases deben ser sustantivos, en mayúsculas y minúsculas, con
la primera letra de cada palabra interna en mayúscula. El nombre de las interfaces
también debe estar en mayúscula (la primera) al igual que los nombres de las
clases. Use palabras completas y debe evitar acrónimos y abreviaturas.

 Métodos en Java

Los métodos deben ser verbos, en mayúsculas y minúsculas, con la primera letra de
cada palabra interna (a partir de la segunda) en mayúscula.

 Variables en Java

Los nombres de las variables deben ser cortos pero significativos.

o No debería comenzar con un guión bajo (‘_’) o caracteres, como, por


ejemplo, un signo de dólar ‘$’.
o Debe ser mnemotécnico, es decir, diseñado para indicar al observador
casual la intención de su uso.
o Se deben evitar los nombres de variable de un carácter, excepto para
variables temporales.
o Los nombres comunes para las variables temporales son: i, j, k, m y n
para enteros; c, d y e para los caracteres.
 Variables constantes en Java

Debería estar todo en mayúsculas con palabras separadas por guiones bajos (“_”).

4
o Hay varias constantes utilizadas en clases predefinidas como Float,
Long, String, etc.
 Paquetes en Java

El prefijo de un nombre de paquete único siempre se escribe en letras ASCII en


minúsculas y debe ser uno de los nombres de dominio de nivel superior, como, por
ejemplo: com, edu, gov, mil, net, org.

o Los componentes posteriores del nombre del paquete varían de


acuerdo con las convenciones internas de nombres de la organización.

1.3 Evitar la creación innecesaria de objetos, Lazy Initialitation


La creación de objetos en Java es una de las operaciones más costosas en
términos de uso de memoria e impacto en el performance. Esto es evitable creando
o inicializando objetos solo en el momento en que serán requeridos en el código.

1.4 Nunca hacer variables de instancia públicas


Hacer una variable de instancia pública puede ocasionar problemas en un
programa. Por ejemplo, si tienes una clase MiCalendario. Esta clase contiene un
arreglo de cadenas diasDeLaSemana. Pero es una arreglo público y este puede ser
accedido por cualquiera. Tu asumes que este arreglo contiene siempre los 7
nombres de los días de la semana. ¡Alguien por error puede cambiar el valor e
insertar un error!

La mejor práctica como mucho de ustedes saben, es definir siempre estas variables
como privadas y crear los métodos accesores, “setters“ y “getters”

5
Pero escribir los métodos accesores no resuelve el problema del todo. El arreglo
sigue siendo accesible. La mejor forma de hacerlo inmodificable es devolviendo un
arreglo clonado en lugar del arreglo mismo. Esto se logra modificando el método
get de la siguiente forma.

Trata siempre de minimizar la Mutabilidad de las clases

1.5 Trata siempre de minimizar la Mutabilidad de las clases


Hacer una clase inmutable es hacerla inmodificable. La información de la clase se
preservará durante el tiempo de vida de la clase. Las clases inmutables son simples
y fáciles de manejar. Son “thread safe”. Normalmente son los bloques que
permiten formar otros objetos más grandes.

No obstante, crear objetos inmutables pueden golpear significativamente el


rendimiento de una aplicación. Así que elije cuidadosamente si quieres que una
clase sea o no inmutable. Trata siempre de tener clases pequeñas con el menor
número de clases inmutables.

Para hacer una clase inmutable puedes definir sus constructor de forma privada y
luego crear un método estático para inicializar al objeto y devolverlo.

6
1.6 Trata de usar más las Interfaces sobre las Clases Abstractas
No es posible la herencia múltiple en Java, pero definitivamente puedes
implementar múltiples interfaces. Esto hace que cambiar la implementación de una
clase existente sea fácil y que puedas implementar una o más interfaces en lugar de
cambiar la jerarquía completa de la clase.

Pero si tú estás cien por ciento seguro de que métodos de una interface tendrás,
entonces solo implementa esa interfaz. Es bastante difícil agregar un nuevo
método en una interfaz existente sin alterar todo el código que se está
implementando. Por el contrario, un nuevo método puede ser fácilmente agregado
en una clase abstracta sin alterar la funcionalidad existente.

1.7 Limita siempre el alcance de una variable local


Las variables locales son grandiosas. Pero algunas veces pueden insertar más
bugs durante el copiado y pegado de código viejo. Minimizar el alcance de una
variable local hace que el código sea más legible, menos propenso a errores y más
mantenible.

Por lo tanto, debemos declarar variables justo antes de ser usadas.

Procura inicializar una variable desde su declaración. Si eso no es posible asígnale


el valor nulo.

1.8 Trata de usar librerías estándar en lugar de hacer las tuyas desde cero
Escribir código es divertido. Pero no reinventes la rueda. Es bastante
recomendable usar librerías estándar que ya han sido probadas, debugeadas y
usadas por otros. Esto no sólo mejora la eficiencia de un programador, sino que
reduce las posibilidades de tener errores en el código. Además, usar una librería
estándar hace al código más legible y mantenible.

Por ejemplo, Google tiene liberada la nueva librería Google Collections que puede
ser usada para agregar más funcionalidad a tu código.

7
1.9 Siempre que sea posible trata de usar tipos primitivos en lugar de las
clases Wrapper
Las clases Wrapper son buenas, pero también son lentas. Los tipos primitivos son
como clases, sin embargo, las clases wrapper almacenan la información completa
acerca de una clase.

Algunas veces un programador puede agregar un error en el código usando una


wrapper por un descuido. Por ejemplo:

El primer [Link] imprimirá true mientras que el segundo imprimirá false.


El problema cuando comparas dos clases wrapper es que no se puede usar el
operador ==, porque en realidad se están comparando referencias y no sus valores
actuales.

Además, si estás usando una clase wrapper no debes olvidar inicializarla. Porque el
valor por default de las variables wrapper es null.

El código lanzará un NullPointerException cuando se trate de comparar con true y el


valor sea nulo si en el código intermedio no fue inicializada.

8
1.10 Usa los Strings con mucho cuidado
Usa siempre las cadenas con mucho cuidado en tu código. Una simple
concatenación de cadenas puede reducir el rendimiento de tu programa. Por
ejemplo, si queremos concatenar cadenas usando el operador “+” en un ciclo for
entonces todo el tiempo se estará creando un objeto String. Esto afecta tanto a la
memoria como al rendimiento.

Además, en lugar de que instancies una objeto String no uses su constructor, sino
que debes instanciarlo directamente. Por ejemplo:

1.11 Siempre regresa colecciones vacías en lugar de nulas


No importa que tu método regrese una colección o un arreglo, siempre asegúrate de
que cuando sea necesario se regrese vacío y no nulo, en aquellos casos en los que
no contendrá elementos porque la lógica de tu programa lo requiera. Esto te
ahorrará un montón de tiempo cuando hagas pruebas para valores nulos.

1.12 El copiado defensivo es salvador


El copiado defensivo hace que los objetos creados estén libres de la mutación. Por
ejemplo, en el código siguiente tenemos definida la clase Estudiante la cual a su vez
tiene una variable con la fecha de nacimiento que es inicializada cuando el objeto es
construido.

9
Ahora podríamos tener el siguiente código que use al objeto Estudiante.

En el código siguiente creamos tan solo al objeto Estudiante con algunas fechas de
nacimiento por default. Pero entonces cambiamos el valor del año de nacimiento.
¡Después imprimimos el año de nacimiento, este año fue cambiado por 2019!

Para evitar estos casos, se puede utilizar el mecanismo defensivo copias. Cambie el
constructor de la clase del estudiante a lo siguiente.

Esto para asegurarnos de tener otra copia de la fecha de nacimiento que usamos en
clase Estudiante.

1.13 Nunca dejes salir una excepción de un bloque finally

1.14 Nunca lances «Exception» directamente.

1.15 No inicializar una variable String con (‘ ’), si no con (“ ”)

10
2. VARIABLES

2.1 Tipo de variables

2.2 Inferencia de tipos para variables locales (Uso de “var”)


La palabra reservada “var”, ayuda a no tener que repetir varias veces los tipos en la
construcción de un objeto. En las lambdas los parámetros no es necesario

11
declararlos infiriéndose de la interfaz que implementan. La inferencia de tipos es la
idea que permite al compilador obtener el tipo estático sin que sea necesario
escribirlo de forma explícita.

1. Podemos declarar cualquier tipo de datos con la palabra clave var.

2. var se puede utilizar en una declaración de variable local.

3. var no se puede utilizar en una instancia y en una declaración de variable global.

4. var no se puede utilizar como tipo genérico.

5. var no se puede utilizar con el tipo genérico.

6. var no se puede utilizar sin una inicialización explícita.

7. var no se puede utilizar con Lambda Expression.

8. var no se puede utilizar para parámetros de método y tipo de retorno.

12
3. CARACTERES ESPECIALES

Acción Representación
Salto de línea \n
Tabulador \t
Retroceso \b
Comilla simple \’
Comilla doble \”
Ir al principio de la línea \r
Nueva página \f
Barra inversa \\
Carácter Unicode. \udddd
Espacio \s

4. OPERADORES (Todos)

4.1 Aritméticos
Nombre Operador Acción
Suma + Suma
Resta - Resta
Multiplicación * Multiplica
División / Divide
Módulo o Resto % Obtiene el residuo de la
división

4.2 Relación
Nombre Operador Acción
Menos que < Menos que: el resultado
verdadero si el valor del
lado izquierdo es inferior al
del lado derecho.
Mayor que > Mayor que: devuelve
verdadero si el valor del
lado izquierdo es mayor que

13
el lado derecho.
Menor o igual que <= Menor o igual que:
devuelve verdadero si el
valor del lado izquierdo es
menor o igual que el lado
derecho.
Mayor o igual a >= Mayor que o igual a:
regresa verdadero si el valor
del lado izquierdo es mayor
o igual que el lado derecho.
No igual a: != No igual a: devuelve
verdadero si el valor del
lado izquierdo no es igual al
lado derecho.
Operador de igualdad == Igual a: devuelve verdadero
si el valor del lado izquierdo
es igual al lado derecho

4.3 Lógicos
Nombre Operador Acción
Operador condicional doble && Todas tienen que cumplir
(AND) con la condición (Evalúa en
modo corto circuito)
Operador condicional & Todas tienen que cumplir
simples (AND) con la condición (Evalúa
todas los condicionales)
Operador condicional doble || Por lo menos alguna tiene
(OR) que cumplir con la condición
(Evalúa en modo corto
circuito)
Operador condicional | Por lo menos alguna tiene
simples (OR) que cumplir con la condición
(Evalúa todas los
condicionales)

14
Operador unitario de ! Invierte el valor de una
negación variable booleana
Operador XOR ^ Devuelve true si ambos
valores son diferentes; de lo
contrario, devuelve false.

4.4 Unitarios
Nombre Operador Acción
Operador bit a bit de ~ Este es un operador unario
complemento (NOT) que devuelve la
representación
complementaria del valor de
entrada, es decir, con todos
los bits invertidos. El
resultado binario final se
muestra en decimal.
Operador de decremento - Cambie el signo de la
variable:
(Se coloca a la izquierda de
la variable)

4.5 A nivel de bits

Nombre Operador Acción


Operador bit a bit AND & Si ambos bits de entrada
son 1, establece el
resultado en 1. De lo
contrario da como resultado
0. El resultado binario final
se muestra en decimal
Operador bit a bit OR | Si al menos uno de los dos
bits de entrada es 1,
establece el resultado en 1.
De lo contrario da como

15
resultado 0. El resultado
binario final se muestra en
decimal.
Operador bit a bit XOR ^ Si uno de los bits de entrada
es 0 y el otro 1, el resultado
es 1. Si ambos bits
comparados son iguales, el
resultado es 0. El resultado
binario final se muestra en
decimal.
Operador de << desplaza los bits del número
desplazamiento a la hacia la izquierda y llena
izquierda con “0” los bits desplazados.
Efecto similar a la
multiplicación del número
con una potencia de dos.
Operador de >> Desplaza los bits del
desplazamiento a la número a la derecha y llena
derecha firmado con “0” los bits desplazados.
El bit más a la izquierda
depende del signo del
número inicial. Efecto
similar a partir de dividir el
número con alguna potencia
de dos.
Operador de cambio a la >>> Desplaza los bits del
derecha sin signo número a la derecha y llena
con “0” los bits desplazados.
El bit más a la izquierda se
establece en 0.

4.6 Asignación
Nombre Operador Acción
Operador de incremento - ++ Incrementa el valor en 1
pre incremento y pos

16
incremento

Operador de decremento -- Decrementa el valor en 1


(Las mismas características
del operador de incremento)
Operador de asignación = Se asigna un valor a una
variable
+=
-=
*=
/=
%=
<<=
>>=
operador de asignación (a = a + 1;) Es los mismo
>>>=
compuesta que: (a +=1;)
&=
|=
^= (para aumentar la
potencia del operando
izquierdo al operando
derecho y asignarlo a la
variable de la izquierda.)

4.7 Condicional
Nombre Operador Acción
Operador ?: Simplifica el If else en una simple línea de código:
ternario

17
4.8 Jerarquía
La regla de precedencia establece que los operadores de mayor nivel se ejecuten
primero:

Precedencia de operadores

Descripción Operadores

operadores posfijos op++ op--

operadores unarios ++op --op +op -op ~ !

multiplicación y división */%

suma y resta +-

desplazamiento << >> >>>

operadores relacionales < > <= =>

equivalencia == !=

operador AND &

operador XOR ^

operador OR |

AND booleano &&

OR booleano ||

condicional ?:

operadores de asignación = += -= *= /= %= &= ^= |= <<= >>= >>>=

18
5. USO DE BREACK Y CONTINUE
En java hay dos sentencias que nos permiten forzar la salida de un bucle, y estas
sentencias son break (para salir completamente del bucle) y continue (para salir de
la iteración actual y saltar directamente a la siguiente).

Estas instrucciones siempre irán dentro de algún if (o else) porque carece de sentido
si se va a ejecutar siempre pues en ese caso está claro que hay algo que estamos
haciendo mal porque una parte de nuestro código no llegará a ejecutarse nunca.

5.1 break
La sentencia break hace que se salga del bucle inmediatamente por lo que no se
ejecutara ni el código que se encuentre después del break en esa misma iteración ni
ninguna de las posibles iteraciones restantes.

Esta sentencia no es exclusiva para los bucles y de hecho su uso más conocido es
dentro de un switch.

19
5.2 continue
Con continue se puede detener la ejecución de la iteración actual y saltar a la
siguiente. El caso normal de uso de continue es cuando dentro de un bucle estamos
haciendo muchas comprobaciones y en caso de que se cumpla alguna no hace falta
seguir comprobando el resto, pero no queremos meter unas comprobaciones
anidadas dentro de otras para una mayor legibilidad.

La sentencia continue siempre tiene que estar dentro de un bucle porque si no


producirá un error de compilación, en cualquier caso, no tiene sentido ponerla fuera
de un bucle.

5.3 break y continue con etiqueta (Es una mala práctica)


Tanto break como continue se pueden usar con etiquetas para hacer que en lugar
de simplemente salir del bucle o saltar a la siguiente iteración como ocurre cuando
los usamos sin ninguna etiqueta (como en los ejemplos anteriores) salten a la parte
del código donde indique la etiqueta.

La etiqueta no puede estar en cualquier parte de nuestro código por lo que no


vamos a poder hacer saltos condicionales puros tipo goto, sino que solo podremos
hacer saltos a bucles dentro de los que nos encontremos. ¿Y eso no es lo mismo
que hemos estado haciendo? La respuesta es... depende con los ejemplos
anteriores podemos salir del bucle que contiene la palabra continue o break, pero si
usamos etiquetas podemos salir a otro bucle superior que contenga el bucle que si
que contiene el break o continue.

20
6. PRECEDENCIA DE OPERADORES (PRIORIDAD Y ORDEN DE
EVALUACIÓN)

21
7. MEMORIA STACK Y HEAP

8. PROGRAMACIÓN ORIENTADA A OBJETOS (POO)

8.1 Sobrecarga de constructores


La sobrecarga de constructor es una técnica en Java en la que una clase puede
tener cualquier cantidad de constructores que difieran en la lista de parámetros. El
compilador diferencia estos constructores teniendo en cuenta el número de
parámetros en la lista y su tipo.

8.2 Sobrecarga de métodos


La sobrecarga de métodos es la creación de varios métodos con el mismo nombre,
pero con diferente lista de tipos de parámetros. Java utiliza el número y tipo de
parámetros para seleccionar cuál definición de método ejecutar.

22
8.3 Modificadores de acceso
 Default (Es invisible)

Si no especificamos ningún modificador de acceso se utiliza el nivel de acceso por


defecto, que consiste en que el elemento puede ser accedido sólo desde las clases
que pertenezcan al mismo paquete.

 Publico (public)

El nivel de acceso public permite a acceder al elemento desde cualquier clase,


independientemente de que esta pertenezca o no al paquete en que se encuentra el
elemento.

 Privado (private)

private, por otro lado, es el modificador más restrictivo y especifica que los
elementos que lo utilizan sólo pueden ser accedidos desde la clase en la que se
encuentran. Este modificador sólo puede utilizarse sobre los miembros de una clase
y sobre interfaces y clases internas, no sobre clases o interfaces de primer nivel,
dado que esto no tendría sentido.

Es importante destacar también que private convierte los elementos en privados


para otras clases, no para otras instancias de la clase. Es decir, un objeto de una
determinada clase puede acceder a los miembros privados de otro objeto de la
misma clase, por lo que algo como lo siguiente sería perfectamente válido:

 Protegido (protected)

El modificador protected, por último, indica que los elementos sólo pueden ser
accedidos desde su mismo paquete (como el acceso por defecto) y desde cualquier
clase que extienda la clase en que se encuentra, independientemente de si esta se
encuentra en el mismo paquete o no. Este modificador, como private, no tiene
sentido a nivel de clases o interfaces no internas.

23
8.4 Miembros estáticos de una clase
Para definir una propiedad o método estático en lenguaje Java se antepone el
modificador static a su nombre.

Las propiedades estáticas de una Clase son compartidas por todos los Objetos que
heredan de ella, con lo que si su valor es modificado en cualquier de ellos afectará a
todas las demás instancias.

El mencionado modificador static es utilizado también para declarar constantes o


propiedades cuyo valor no puede ser modificado una vez definido.

Por otro lado, para acceder a los métodos estáticos de una clase no es necesario
crear un objeto, pudiendo acceder a ellos a través del propio nombre de clase.

Un Atributo static:

No es específico de cada objeto. Solo hay una copia de este y su valor es


compartido por todos los objetos de la clase.

Podemos considerarlo como una variable global a la que tienen acceso todos los
objetos de la clase.

Existe y puede utilizarse, aunque no existan objetos de la clase.

Para acceder a un atributo de clase se escibe:

[Link]

Un Método static:

Tiene acceso solo a los atributos estáticos de la clase.

No es necesario instanciar un objeto para poder utilizarlo.

Para acceder a un método de clase se escribe:

24
NombreClase.método()

8.5 Herencia (extends)


Es el mecanismo en Java por el cual una clase permite heredar las características
(atributos y métodos) de otra clase.

En el lenguaje de Java, una clase que se hereda se denomina superclase. La clase


que hereda se llama subclase. Por lo tanto, una subclase es una versión
especializada de una superclase. Hereda todas las variables y métodos definidos
por la superclase y agrega sus propios elementos únicos.

Terminología importante

 Superclase: la clase cuyas características se heredan se conoce como


superclase (o una clase base o una clase principal).
 Subclase: la clase que hereda la otra clase se conoce como subclase (o una
clase derivada, clase extendida o clase hija). La subclase puede agregar sus
propios campos y métodos además de los campos y métodos de la
superclase.
 Reutilización: la herencia respalda el concepto de “reutilización”, es decir,
cuando queremos crear una clase nueva y ya hay una clase que incluye parte
del código que queremos, podemos derivar nuestra nueva clase de la clase
existente. Al hacer esto, estamos reutilizando los campos/atributos y métodos
de la clase existente.

¿Qué es Herencia?

Podemos definir la herencia como la capacidad de crear clases que adquieren de


manera automática los miembros (atributos y métodos) de otras clases que ya
existen, pudiendo al mismo tiempo añadir atributos y métodos propios.

Tenga en cuenta que durante la herencia solo se crea el objeto de la subclase, no


de la superclase.

25
8.6 Clases y métodos abstractos
Clase abstracta

 Se utilizan solo como super clases.


 No se pueden instanciar objectos de la forma tradicional (Es recomendable
no hacerlo, es mejor practica solo instanciar de las clases hijas que no son
abstractas).
 Sirven para proporcionar una super clase apropiada a partir de la cual
heredan otras clases.

Métodos abstractos

 No tiene cuerpo (llaves): sólo consta de signatura con paréntesis.


 Su signatura termina con un punto y coma.
 Sólo puede existir dentro de una clase abstracta. De esta forma se evita que
haya métodos que no se puedan ejecutar dentro de clases concretas. Visto
de otra manera, si una clase incluye un método abstracto, forzosamente la
clase será una clase abstracta.
 Los métodos abstractos forzosamente habrán de estar sobreescritos en las
subclases. Si una subclase no implementa un método abstracto de la
superclase tiene un método no ejecutable, lo que la fuerza a ser una subclase
abstracta. Para que la subclase sea concreta habrá de implementar métodos
sobreescritos para todos los métodos abstractos de sus superclases.

Diferencia entre clase abstracta y clase concreta en java

 Clase abstracta: una clase abstracta es un tipo de clase en Java que se


declara mediante la palabra clave abstracta. Una clase abstracta no se puede
instanciar directamente, es decir, el objeto de dicha clase no se puede crear
directamente usando la nueva palabra clave. Se puede crear una instancia de
una clase abstracta mediante una subclase concreta o definiendo todo el
método abstracto junto con la nueva declaración. Puede contener o no un
método abstracto. Un método abstracto es declarado por palabra clave
abstracta, tales métodos no pueden tener cuerpo. Si una clase contiene un
método abstracto, también debe ser abstracto.
 Clase concreta: una clase concreta en Java es un tipo de subclase, que
implementa todo el método abstracto de su clase súper abstracta a la que se

26
extiende. También tiene implementaciones de todos los métodos de
interfaces que implementa.

8.7 Interfaces
 Permiten simular la herencia múltiple
 La interfaz solo es public o default
 Las interfaces no heredan de la clase object
 Las intefaces no tienen constructores
 Todos sus métodos son públicos y abstractos
 Todos sus atributos son constantes (public, static y final)
 Cuando creamos una interface, el nombre del archivo comienza con “I”,
ejemplo: IAccesoDatos

Una interfaz (interface) es sintácticamente similar a una clase abstracta, en la que


puede especificar uno o más métodos que no tienen cuerpo ({}). Esos métodos
deben ser implementados por una clase para que se definan sus acciones.

Por lo tanto, una interfaz especifica qué se debe hacer, pero no cómo hacerlo. Una
vez que se define una interfaz, cualquier cantidad de clases puede implementarla.
Además, una clase puede implementar cualquier cantidad de interfaces.

Para implementar una interfaz, una clase debe proporcionar cuerpos


(implementaciones) para los métodos descritos por la interfaz. Cada clase es libre
de determinar los detalles de su propia implementación. Dos clases pueden
implementar la misma interfaz de diferentes maneras, pero cada clase aún admite el
mismo conjunto de métodos. Por lo tanto, el código que tiene conocimiento de la
interfaz puede usar objetos de cualquier clase, ya que la interfaz con esos objetos
es la misma.

27
8.8 Diferencia entre clase e interfaz

¿Cuándo usar Interface y Abstract Class?

 Use una clase abstracta cuando se necesita definir una plantilla para un
grupo de subclases
 Use una interfaz cuando se debe definir un rol para otras clases,
independientemente del árbol de herencia de estas clases

Debe conocer hechos sobre Interface

 Una clase Java puede implementar múltiples interfaces Java. Es necesario


que la clase implemente todos los métodos declarados en las interfaces.
 La clase debe anular todos los métodos abstractos declarados en la interfaz
 La interfaz permite enviar un mensaje a un objeto sin importar a qué clases
pertenece.
 La clase necesita proporcionar funcionalidad para los métodos declarados en
la interfaz.
 Todos los métodos en una interfaz son implícitamente públicos y abstractos
 Una interfaz no puede ser instanciada
 Una referencia de interfaz puede señalar objetos de sus clases de
implementación
 Una interfaz puede extenderse desde una o varias interfaces. La clase puede
extender solo una clase, pero implementar cualquier cantidad de interfaces
 Una interfaz no puede implementar otra interfaz. Tiene que ampliar otra
interfaz si es necesario.
 Una interfaz que se declara dentro de otra interfaz se denomina interfaz
anidada

28
 En el momento de la declaración, la variable de interfaz debe inicializarse. De
lo contrario, el compilador lanzará un error.
 La clase no puede implementar dos interfaces en Java que tengan métodos
con el mismo nombre, pero diferente tipo de devolución.

Resumen:

 La clase que implementa la interfaz necesita proporcionar funcionalidad para


los métodos declarados en la interfaz
 Todos los métodos en una interfaz son implícitamente públicos y abstractos
 Una interfaz no puede ser instanciada
 Una referencia de interfaz puede señalar objetos de sus clases de
implementación
 Una interfaz puede extenderse desde una o varias interfaces. Una clase
puede extender solo una clase, pero implementar cualquier cantidad de
interfaces

8.9 Polimorfismo
El polimorfismo es una característica de la programación orientada a objetos que
permite llamar a métodos con igual nombre pero que pertenecen a clases distintas.

En Java es necesario que las clases compartan una superclase común para
implementar el polimorfismo, luego veremos que también se puede implementar el
polimorfismo en Java mediante interfaces.

Con el polimorfismo podemos implementar programas que luego son fácilmente


extensibles.

Ejemplo:

29
8.10 Upcasting vs Downcasting
La tipificación es uno de los conceptos más importantes que básicamente se ocupa
de la conversión de un tipo de datos a otro de forma implícita o explícita. En este
artículo, se analiza el concepto de encasillamiento de objetos.

Al igual que los tipos de datos, los objetos también se pueden tipificar. Sin embargo,
en los objetos, solo hay dos tipos de objetos (es decir, objeto principal y objeto
secundario). Por lo tanto, el encasillado de objetos significa básicamente que un tipo
de objeto (es decir) hijo o padre de otro. Hay dos tipos de encasillamiento. Son:

30
 Upcasting: Upcasting es el encasillado de un objeto hijo a un objeto padre .
El upcasting se puede hacer implícitamente. Upcasting nos da la flexibilidad
de acceder a los miembros de la clase principal, pero no es posible acceder a
todos los miembros de la clase secundaria utilizando esta función. En lugar
de todos los miembros, podemos acceder a algunos miembros específicos de
la clase secundaria. Por ejemplo, podemos acceder a los métodos anulados.
 Downcasting: De manera similar, downcasting significa encasillar un objeto
padre a un objeto hijo . El abatimiento no puede ser implícito.

8.11 Uso de la palabra “super”


java, la aplicación utiliza super para referirse a una variable local en un método y a
una variable de la superclase que tiene el mismo nombre. El programa también

31
utiliza super para invocar al constructor de la superclase desde en constructor de la
subclase.

8.12 Uso de la palabra “final”


Indica que una variable, método o clase no se va a modificar, lo cuál puede ser útil
para añadir más semántica, por cuestiones de rendimiento, y para detectar errores.

Si una variable se marca como final, no se podrá asignar un nuevo valor o


referencia a la variable. Si una clase se marca como final, no se podrá extender la
clase. Si es un método el que se declara final, no se podrá sobreescribir.

Una variable con modificadores static y final sería lo más cercano en Java a las
constantes de otros lenguajes de programación.

32
9. PROGRAMACIÓN EN JAVA

9.1 Varargs: Argumentos Variables en Java


Algunas veces querrá crear un método que tome una cantidad variable de
argumentos, según su uso preciso. Por ejemplo, un método que abre una conexión
a Internet puede tomar un nombre de usuario, contraseña, nombre de archivo,
protocolo, etc., pero proporcionará los valores predeterminados si no se proporciona
parte de esta información.

En esta situación, sería conveniente pasar solo los argumentos a los que no se
aplicaron los valores predeterminados. Crear dicho método implica que debe haber
alguna forma de crear una lista de argumentos que sea de longitud variable, en
lugar de fija.

Salida:

33
NOTA: Si existen varios parámetros, el parámetro variable debe ser el último.

9.2 Enum: Enumeraciones


Las enumeraciones o enum en un lenguaje de programación sirven para representar
un grupo de constantes con un nombre. Veamos algunos ejemplos para comprender
mejor.

En su forma más simple, una enumeración es una lista de constantes con nombre
que definen un nuevo tipo de datos. Un objeto de un tipo de enumeración solo
puede contener los valores definidos por la lista. Por lo tanto, una enumeración le
brinda una manera de definir con precisión un nuevo tipo de datos que tiene un
número fijo de valores válidos.

Desde una perspectiva de programación, las enumeraciones son útiles siempre que
necesite definir un conjunto de valores que represente una colección de elementos.
Por ejemplo, puede usar una enumeración para representar un conjunto de códigos
de estado, como éxito, espera, error y reintentos, que indican el progreso de alguna
acción. En el pasado, dichos valores se definían como variables finales, pero las
enumeraciones ofrecen un enfoque más estructurado.

En Java (desde 1.5), las enumeraciones se representan utilizando el tipo de datos


enum. Las enumeraciones Java son más poderosas que las enumeraciones C/C++.
En Java, también podemos agregarle variables, métodos y constructores. El objetivo
principal de enum es definir nuestros propios tipos de datos (tipos de datos
enumerados).

Ejemplo:

34
Enun con constructores y métodos:

9.3 Bloques de inicialización estáticos y no estáticos


Estos bloques de inicialización se van a ejecutar antes del constructor, primero los
bloques estáticos y después los no estáticos. Por lo tanto, el bloque estático solo se
ejecutará una vez al momento de cargar la clase en memoria.

Ejemplo:

35
Clase:

Main:

Salida:

36
9.4 Autoboxing y Unboxing
A partir de JDK 5, Java ha incluido dos características muy útiles: autoboxing y auto-
unboxing. El autoboxing/unboxing simplifica y agiliza en gran medida el código que
debe convertir los tipos primitivos en objetos, y viceversa. Debido a que tales
situaciones se encuentran con frecuencia en el código de Java, los beneficios del
autoboxing/unboxing afectan a casi todos los programadores de Java.

Autoboxing/unboxing está directamente relacionado con los wrappers de Java y


con la forma en que los valores se mueven dentro y fuera de una instancia de un
wrapper (envoltorio). Por esta razón, comenzaremos con una descripción general de
los tipos de wrappers y el proceso boxing y unboxing manual de los valores.

Cada uno de los tipos primitivos tiene una clase en java asociada conocida como
clase Wrapper o Envolvente

Clase envolvente de tipo primitivo:

Al utilizar una clase envolvente, en vez de un dato primitivo, podemos acceder a


varios métodos muy útiles.

37
Ejemplo:

El termino Autoboxing se presentan cuando la literal primitiva de un tipo entero, se


convierte a un tipo object:

El termino de Unboxing funciona de manera inversa al autoboxing, y se representa


de la siguiente manera:

9.5 InstanceOf
Las palabra “instance of” nos ayudará a determinar el tipo de un objecto en tiempo
de ejecución, por lo tanto, esta palabra nos permitirá realizar la siguiente pregunta:
¿De qué tipo es la referencia a la cual está apuntando cierta variable?

Nota: El tipo de una variable es la referencia que almacene, ejemplo:

En este caso las dos variables son de tipo Son, aunque la segunda se halla
almacenado en una variable de tipo Father, lo importante es el tipo la referencia.

A continuación, unos ejemplos del uso de la palabra reservada “instanceof”

Ejemplo 1

38
Entrada:

Salida:

Ejemplo 2

Entrada:

Salida:

Ejemplo 3

Entrada:

39
Salida:

Ejemplo 4

Entrada:

Salida:

40
Ejemplo 5

En este caso, instanceof devuelve false porque la referencia es de tipo Animal, y


puede apuntar tanto a un objeto de tipo Perro, como de tipo Gato. Quizá te digas
"ya, lo he entendido, ¿qué otra cosa podría hacer instanceof?". La respuesta es muy
fácil: podría no compilar.

Recuerda: instanceof solo devuelve false en dos casos

La razón es sencilla: cuando se utiliza una clase, como en este caso, instanceof solo
devuelve false en dos casos:

Cuando la referencia no apunta a ningún objeto (valor null).

Cuando la referencia es de una superclase. Es decir, tienes una referencia de tipo


Animal, que podría ser un Perro o un Gato.

En el resto de las ocasiones, o el valor es true, o el código no compila. En realidad,


puedes entenderlo de este modo: el código solo compila si el valor de instanceof es
true. Si existen estas dos excepciones, es porque el compilador no sabe si la
referencia es null, o a qué tipo de subclase apunta. Incluso si marcas la referencia
como final, el código compila y devuelve false.

Si el objeto al que apunta la referencia ni es un Animal ni puede serlo, el


código no compila:

41
9.6 JavaBeans
Para que una clase en java se considere “JavaBean” debe de tener las siguientes
características:

 Debe tener un constructor vacío


 Cada uno de sus atributos debe ser privado
 Cada uno de sus atributos deber tener sus métodos getter y setter
respectivos
 Debe implementar la interface “Serializable” (Esta interface nos va a permitir
enviar nuestra clase entre diferentes equipos / servidores)

Las JavaBean son utilizadas en tecnologías como Java EE y frameworks.

Ejemplo de JavaBean:

42
9.7 Excepciones (Exception)
El lenguaje Java utiliza excepciones para proporcionar posibilidades de manejo de
errores para sus programas. Una excepción es un evento que se produce cuando se
ejecuta el programa de forma que interrumpe el flujo normal de instrucciones.

El sistema de ejecución Java y muchas clases de paquetes Java lanzan


excepciones en algunas circunstancias utilizando la sentencia throw. Puede utilizar
el mismo mecanismo para lanzar excepciones en los programas Java.

¿Cómo capturar una excepción?

Salida:

Hay casos en donde se presentan cadenas de excepciones, y una excepción hace


que se produzca otra excepción, por lo tanto, es recomendable usar el método
“printStackTrace([Link])” para visualizar ese posible árbol.

Cuando en Java se produce una excepción se crear un objeto de una determina


clase (dependiendo del tipo de error que se haya producido), que mantendrá la
información sobre el error producido y nos proporcionará los métodos necesarios
para obtener dicha información. Estas clases tienen como clase padre la clase
Throwable, por tanto, se mantiene una jerarquía en las excepciones. A continuación,
mostramos algunas de las clases para que nos hagamos una idea de la jerarquía
que siguen las excepciones, pero existen muchísimas más excepciones que las que
mostramos:

43
Nota: Si la clase hereda de “Exception”, el compilador nos obliga a porcesar la
exception, sin embargo, si heredamos de la clase “RuntimeException” el compilador
no nos obligará a capturar la excepción (Esto lo podemos evidenciar en las
operaciones sobre “0”, ya que el compilador nos permite realizar la operación, y el
error solo salta cuando se ejecuta el programa).

¿Cómo crear nuestras propias excepciones?

Primero deberemos crear una clase que herede de Exception:

Después creamos la clase en donde se presentará la excepción:

Para probarla hacemos lo siguiente:

44
Salida:

Ahora vamos a ver como seria la creación de la excepción en el caso de usar


RuntimeException, y no Exception:

Las únicas diferencias son las siguientes:

 El compilador ya no nos obliga a capturar la excepción


 La clase de la excepción ya no extiende de Exception, si no de
RuntimeException:

 Ya no es necesario arrojar la excepción en la firma del método de la clase


aritmética:

45
Finalmente, al utilizar el método, el compilador no nos obligará a capturar la
excepción:

Salida:

9.8 API de Collections


Colletions

Esta interfaz es “la raíz” de todas las interfaces y clases relacionadas con
colecciones de elementos. Algunas colecciones pueden admitir duplicados de
elementos dentro de ellas, mientras que otras no admiten duplicados. Otras
colecciones pueden tener los elementos ordenados, mientras que en otras no existe
orden definido entre sus elementos. Java no define ninguna implementación de esta
interface y son respectivamente sus subinterfaces las que implementarán sus
métodos como son por ejemplo las interfaces Set o List (que son subinterfaces de
Collection).

46
Una colección es de manera genérica un grupo de objetos llamados elementos.
Esta interfaz por tanto será usada para pasar colecciones de elementos o
manipularlos de la manera más general deseada.

En resumen, la idea es la siguiente: cuando queremos trabajar con un conjunto de


elementos, necesitamos un almacén donde poder guardarlos.

En Java, se emplea la interface genérica Collection para este propósito. Gracias a


esta interface, podemos almacenar cualquier tipo de objeto y podemos usar una
serie de métodos comunes, como pueden ser: añadir, eliminar, obtener el tamaño
de la colección… ya que se trata de métodos definidos por la interface que
obligatoriamente han de implementar las subinterfaces o clases que hereden de
ella.

Collection se ramifica en subinterfaces como Set, List y otras que verémos en


profundidad a lo largo del curso.

Tipos de colecciones

47
El uso de listas en Java es una forma útil de almacenar y manipular grandes
volúmenes de datos, tal como haríamos en una matriz o arreglo, pero con una serie
de ventajas que hacen de este tipo de variables las preferidas para el
procesamiento de grandes cantidades de información.

Las listas en Java son variables que permiten almacenar grandes cantidades de
datos. Son similares a los Array o a las Matrices. Sin embargo, las nuevas
tendencias en la programación van orientadas hacia el uso de Listas para el manejo
de grandes volúmenes de datos. De hecho, Java 8, dentro de sus nuevas
herramientas de programación (específicamente las expresiones Lambda), posee
muchas funcionalidades interesantes implementando listas, lo cuales nos permitirá
lograr muchas cosas fabulosas de una manera mucho más rápida y fácil de lo que
haríamos antes (sin embargo, esto es contenido para otro post).

Esto me ha llevado a buscar formas de agregar las Listas en Java a mis


herramientas de programación. En realidad, no soy muy bueno utilizando este tipo
de variables ya que apenas estoy empezando a utilizarlas, pero siento la necesidad
de compartir lo poco que sé ya que con ello ayudo a otras personas a la vez que
fabrico mi propio cuaderno de apuntes para futuras auto consultas.

Algo que me llama mucho la atención de las listas en Java es el hecho de que no es
necesario establecer un tamaño específico para la variable, a diferencia de las
tradicionales matrices o arreglos. Las listas son sumamente versátiles y mucho más
fáciles de manejar que otros tipos de variables de agrupación de datos.

Entonces… ¿cómo declaramos una lista? Pues seguimos la siguiente estructura:

Este tipo de lista puede almacenar cualquier tipo de dato, pero este enfoque ya ha
quedado obsoleto. Se prefiere que se designe el tipo de dato que se va a
almacenar. Entonces para declarar una lista donde guardaremos datos tipo String,
hacemos lo siguiente:

Con nuestra lista creada podemos empezar a introducir datos en ella.

48
Supongamos que queremos agregar los siguientes nombres: Juan, Pedro, José,
María, Sofía.

Hacemos lo siguiente:

49
Para concluir, en la siguiente imagen se puede apreciar las 3 interfaces principales
de Collection, apartarte de la interfaz Map, para más detalles investigar el uso de
cada intefaz, y sus implementaciones.

9.9 Generics
Hace ya más de una década que en Java 5 se introdujeron los generics para dotar
al lenguaje de una mejor comprobación de tipos en tiempo de compilación y al
mismo tiempo eliminar los cast que hasta entonces eran necesarios al usar las
colecciones. Dada la lentitud de adopción que suele haber en la plataforma Java en
los grandes entornos empresariales puede que aún no los hayamos usado
extensamente o tengamos alguna duda en su uso. Hay unos cuantos conceptos
sobre los generics que son convenientes conocer.

Los generics fueron introducidos en la versión 5 de Java en 2004 junto con otras
muchas novedades suponiendo en su historia una de las mayores modificaciones o
al mismo nivel de las novedades introducidas con Java 8 más recientemente al
lenguaje Java. Los generics son importantes ya que permiten al compilador informar
de muchos errores de compilación que hasta el momento solo se descubrirían en
tiempo de ejecución, al mismo tiempo permiten eliminar los cast simplificando,
reduciendo la repetición y aumentando la legibilidad el código. Los errores por cast

50
inválido son especialmente problemáticos de debuggear ya que el error se suele
producir en un sitio alejado del de la causa.

Los generics permiten usar tipos para parametrizar las clases, interfaces y métodos
al definirlas. Los beneficios son:

 Comprobación de tipos más fuerte en tiempo de compilación.


 Eliminación de casts aumentando la legibilidad del código.
 Posibilidad de implementar algoritmos genéricos, con tipado seguro.

Un tipo usando generics tiene el siguiente aspecto, por ejemplo, usando una clase
Box contenedor de una referencia a un tipo no determinado en la definición de la
clase pero que lo será en su uso. Una clase genérica puede tener múltiples
argumentos de tipos y los argumentos pueden ser a su vez tipos genéricos.
Después del nombre de la clase se puede indicar la lista de parámetros de tipos con
el formato \<T1, T2, T3, ...\>.

Según las convenciones los nombres de los parámetros de tipo usados


comúnmente son los siguientes:

 E: elemento de una colección.


 K: clave.
 N: número.
 T: tipo.
 V: valor.
 S, U, V etc: para segundos, terceros y cuartos tipos.

Los generics tiene algunas restricciones:

 No se pueden instanciar tipos genéricos con tipos primitivos.


 No se pueden crear instancias de los parámetros de tipo.
 No se pueden declarar campos static cuyos tipos son parámetros de tipo.
 No se pueden usar casts o instanceof con tipos parametrizados.
 No se pueden crear arrays de tipos parametrizados.
 No se pueden crear, capturar o lanzar tipos parametrizados que extiendan de
Throwable.
 No se puede sobrecargar un método que tengan la misma firma que otro
después del type erasure.

51
A continuación, veremos un breve ejemplo de tipos genéricos:

Creación de clase genérica:

Método main:

52

También podría gustarte