apuntes:genericos
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
Next revision | |||
— | apuntes:genericos [2021/03/10 13:16] – created Santiago Faci | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Genéricos ====== | ||
+ | |||
+ | \section{Genéricos} | ||
+ | |||
+ | El uso más conocido de los genéricos lo vimos en el tema anterior, con las colecciones, | ||
+ | lo que permite que podamos definir estructuras de la siguiente forma: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | List< | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Lo que permite que, si cometemos algún error como este, podamos ser avisados en tiempo de compilación: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | Integer i = listaCadenas.get(0); | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Sin la existencia de los genéricos, la línea anterior sería como esta: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | Integer i = listaCadenas.get(0); | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Y nunca produciría ningún error de compilación en caso de que estuvieramos cometiendo algún error. A este respecto conviene saber que los | ||
+ | genéricos sólo existen a nivel de compilación, | ||
+ | necesarios para que el código pueda ejecutarse sin problemas. | ||
+ | |||
+ | \subsection{Definición de una clase genérica} | ||
+ | |||
+ | El siguiente fragmento de código se correspondería con la definición de una clase genérica: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class Grupo< | ||
+ | private List< | ||
+ | private int limite; | ||
+ | |||
+ | public Grupo(int limite) { | ||
+ | this.limite = limite; | ||
+ | participantes = new ArrayList<> | ||
+ | } | ||
+ | |||
+ | public void anadirParticipante(E participante) { | ||
+ | if (participantes.size() == limite) | ||
+ | return; | ||
+ | |||
+ | participantes.add(participante); | ||
+ | } | ||
+ | |||
+ | public E getParticipante(int posicion) { | ||
+ | return participantes.get(posicion); | ||
+ | } | ||
+ | |||
+ | public int getNumeroParticipantes() { | ||
+ | return participantes.size(); | ||
+ | } | ||
+ | |||
+ | public int getEspacioLibre() { | ||
+ | return (limite - participantes.size()); | ||
+ | } | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | De esa forma, una definición genérica como la anterior, puede emplearse con distintos tipos de datos: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | Grupo< | ||
+ | . . . | ||
+ | Grupo< | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Como has podido ver en la definición, | ||
+ | definida dicha letra en la definición de la clase, se emplea siempre que se quiera hacer referencia al tipo para el que se define dicha | ||
+ | clase genérica. A este respecto se suelen utilizar diferentes letras para diferentes situaciones: | ||
+ | |||
+ | \begin{itemize} | ||
+ | \item \verb E para definir un elemento de una colección | ||
+ | \item \verb K para definir una clave en un mapa | ||
+ | \item \verb V para definir un valor en un mapa | ||
+ | \item \verb T , \verb U para definir tipos de datos (clases) | ||
+ | \end{itemize} | ||
+ | |||
+ | \subsection{Métodos genéricos} | ||
+ | |||
+ | Así como se pueden definir clases genéricas, también podemos definir métodos genéricos dentro de clases que no lo sean: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class Utils { | ||
+ | public <T> T getUltimoElemento(ArrayList< | ||
+ | return lista.get(lista.size() - 1); | ||
+ | } | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | De esa manera, se podrá invocar al método \verb getUltimoElemento | ||
+ | |||
+ | \subsection{El comodín ?} | ||
+ | |||
+ | También se puede utilizar el caracter comodín \verb ? para indicar que se acepta cualquier tipo, definiendo, por ejemplo, como parámetro un | ||
+ | \verb ArrayList | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | . . . | ||
+ | public void metodo(ArrayList<?> | ||
+ | . . . | ||
+ | . . . | ||
+ | } | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Para este caso también podemos aprovecharnos de las características de la herencia para la definición de métodos genéricos, pudiendo definir el uso de la | ||
+ | clase genérica como clase derivada o como superclase de una, haciendo uso de este comodín. | ||
+ | |||
+ | Para aceptar cualquier clase que extienda de una determinada clase: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | . . . | ||
+ | public void Zoo { | ||
+ | . . . | ||
+ | public void anadirAnimales(ArrayList<? | ||
+ | . . . | ||
+ | . . . | ||
+ | } | ||
+ | . . . | ||
+ | } | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Y para aceptar cualquier clase que esté por encima de una determinada clase: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | . . . | ||
+ | public void Zoo { | ||
+ | . . . | ||
+ | public void anadirAnimales(ArrayList<? | ||
+ | . . . | ||
+ | . . . | ||
+ | } | ||
+ | . . . | ||
+ | } | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
+ | |||
+ | De esa manera, podremos invocar al método \verb anadir | ||
+ | que corresponda con la expresión del comodín que acompaña a la declaración de ese \verb ArrayList . Para entender esta parte hay que tener en cuenta el siguiente caso, y es que dadas las | ||
+ | siguientes clases: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class Animal { | ||
+ | . . . | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class Leon extends Animal { | ||
+ | . . . | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class Zoo { | ||
+ | . . . | ||
+ | public void anadirAnimales(ArrayList< | ||
+ | . . . | ||
+ | . . . | ||
+ | } | ||
+ | . . . | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Las siguiente invocaciones producirían un error de compilación por incompatibilidad de tipos: | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | . . . | ||
+ | Zoo zoo = new Zoo(. . .); | ||
+ | . . . | ||
+ | ArrayList< | ||
+ | zoo.anadirAnimales(leones); | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
+ | |||
+ | Es por eso que tenemos que usar lo que se conoce como los comodínes. | ||
+ | |||
+ | Para el caso de las clases genéricas y métodos genéricos también podemos jugar con las características de herencia, utilizando las mismas | ||
+ | expresiones que podemos usar con el comodín, pero con el caracter que empleemos para referirnos a la clase genérica. A diferencia del uso | ||
+ | del comodín \verb ? , podremos hacer referencia a la clase genérica a lo largo de la implementación del método o clase. | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | public class Grupo<E extends Persona> { | ||
+ | private List< | ||
+ | private int limite; | ||
+ | |||
+ | public Grupo(int limite) { | ||
+ | this.limite = limite; | ||
+ | participantes = new ArrayList<> | ||
+ | } | ||
+ | |||
+ | public void anadirParticipante(E participante) { | ||
+ | if (participantes.size() == limite) | ||
+ | return; | ||
+ | |||
+ | participantes.add(participante); | ||
+ | } | ||
+ | |||
+ | public E getParticipante(int posicion) { | ||
+ | return participantes.get(posicion); | ||
+ | } | ||
+ | |||
+ | public int getNumeroParticipantes() { | ||
+ | return participantes.size(); | ||
+ | } | ||
+ | |||
+ | public int getEspacioLibre() { | ||
+ | return (limite - participantes.size()); | ||
+ | } | ||
+ | } | ||
+ | \end{lstlisting} | ||
+ | |||
+ | \begin{lstlisting}[language=java] | ||
+ | . . . | ||
+ | public <T extends Animal> T getAnimal(ArrayList< | ||
+ | . . . | ||
+ | // Podemos hacer rerencia a T como clase genérica | ||
+ | . . . | ||
+ | return T; | ||
+ | } | ||
+ | . . . | ||
+ | \end{lstlisting} | ||
apuntes/genericos.txt · Last modified: 2023/05/28 12:04 by Santiago Faci