847 Shares 8314 views

Java Generics: Descripción y Métodos

Desde su creación, el lenguaje Java ha sufrido muchos cambios, lo que, sin duda, trajo características positivas a su funcionalidad. Uno de esos cambios significativos es la introducción de Java Generic o generalización. Esta funcionalidad ha hecho que el lenguaje no sólo sea más flexible y versátil, sino también mucho más seguro en términos de reducción de tipos de datos.

El hecho es que antes de la introducción de los genéricos, el código genérico en Java podría ser creado, sólo con enlaces de tipo Object. Estos enlaces se pueden asignar a cualquier objeto. Después de todo, todas las clases en Java son descendientes implícitos de la clase Object. Sin embargo, este enfoque es una fuente potencial de muchos errores de seguridad de tipo cuando convierte explícitamente un objeto de objeto al tipo de destino. Cuando se utilizan generalizaciones, todos los lanzamientos se realizan implícita y automáticamente, lo que excluye incluso la posibilidad potencial de errores.

Java Generics: descripción y ejemplo

Examinemos un ejemplo sencillo de aplicar la generalización a la clase usual en la figura siguiente. Y sólo entonces procederemos a un examen detallado de todas las sutilezas y matices de Java Generic.

Observe cómo se declara la clase Pair. Justo después del nombre de la clase, se abren los ángulos, donde se indica la letra T. Es un tipo de marcador de posición que se reemplazará con un tipo específico al crear una instancia de esta clase. Parece esto: Pair obj = new Pair (). Debe tenerse en cuenta que en lugar de T, puede especificar cualquier letra, pero, como regla general, utilice T, V o E.

Nota: A partir de la octava versión de Java, especificando el tipo de destino cuando se declara el enlace, puede dejar vacíos los corchetes angulares en el constructor. Por lo tanto, el ejemplo anterior se puede reescribir de la siguiente manera: Pair obj = new Pair ().

Cuando una clase se declara de esta manera, entonces en este cuerpo, en lugar de tipos específicos de campos, referencias y métodos devueltos por métodos, puede utilizar esta letra. Debido a que T es reemplazado por un tipo específico al crear un objeto de clase, los campos primero y segundo en este caso serán del tipo Integer.

Siguiendo la lógica, los argumentos firstItem y secondItem, pasados al constructor correspondiente, también deben ser del tipo Integer o su subclase. Si intenta pasar un tipo de datos que es diferente de lo que se especificó cuando se creó el objeto, el compilador no omitirá este error. Por lo tanto, el constructor con argumentos al crear el objeto tendrá la siguiente forma: Pair obj = new Pair (nuevo Integer (1), nuevo Integer (2)). Lo mismo se aplica a los argumentos de los métodos setFirst y setSecond. Y como probablemente ya adivinó, los métodos getFirst y getSecond devolverán valores del tipo Integer.

Una clase genérica con varios parámetros de tipo

En clases genéricas, también puede declarar varios parámetros de tipo que se especifican en corchetes angulares, separados por comas. La clase Pair para este caso se presenta en la siguiente figura.

Como puede ver, al crear una instancia de tal clase, se debe especificar el mismo número de tipos que los parámetros en los corchetes angulares. Si está familiarizado con este tipo de estructura de datos como Map, puede notar que se utiliza el mismo principio. Allí, el primer argumento especifica el tipo de la clave y el segundo especifica el tipo del valor. Cabe señalar que los tipos de argumentos pasados a la creación del objeto pueden ser los mismos. Por lo tanto, la siguiente declaración de una instancia de la clase Pair es absolutamente correcta: Pair obj.

Algunas características de generalizaciones

Antes de continuar, debe tenerse en cuenta que el compilador Java no crea versiones diferentes de la clase Pair. De hecho, durante el proceso de compilación, se suprime toda la información sobre el tipo genérico. En su lugar, se emiten los tipos correspondientes, creando una versión especial de la clase Pair. Sin embargo, el programa en sí todavía tiene una única versión generalizada de esta clase. Este proceso se llama en Java tipo genérico de limpieza.

Tomemos nota de un punto importante. Los enlaces a diferentes versiones de la misma clase genérica java no pueden apuntar al mismo objeto. Es decir, digamos que tenemos dos enlaces: Pair obj1 y Pair obj2. Por lo tanto, se produce un error en la línea obj1 = obj2. Aunque ambas variables son del tipo Pair , los objetos a los que se refieren son diferentes. Este es un ejemplo vívido de la seguridad de los tipos en Java Genérico.

Restricciones impuestas a las clases generalizadas

Es importante saber que las generalizaciones sólo pueden aplicarse a tipos de referencia, es decir, el argumento pasado al argumento java de clase genérica debe ser necesariamente el tipo de la clase. Tales tipos simples como, por ejemplo, dobles o largos, no pueden ser transmitidos. En otras palabras, la siguiente línea de la declaración de clase Pair no es válida: Pair obj. Sin embargo, esta limitación no es un problema grave, ya que Java tiene una clase de contenedor correspondiente para cada tipo primitivo. Estrictamente hablando, si desea encapsular un entero y un valor lógico en la clase Pair, el auto-pack lo hará todo para usted: Pair obj = new Pair (25, true).

Otra limitación seria es la imposibilidad de crear una instancia de un parámetro de tipo. Por lo tanto, la línea siguiente provocará un error de compilación: T first = new T (). Esto es obvio, ya que no se sabe de antemano si una clase completa o una interfaz abstracta se pasará como un argumento. Lo mismo ocurre con la creación de matrices.

Tipos limitados

Muy a menudo hay situaciones en las que es necesario limitar la lista de tipos que se pueden pasar como un argumento a la clase java genérica. Supongamos que en nuestra clase Pair queremos encapsular sólo valores numéricos para operaciones matemáticas adicionales sobre ellos. Para ello, necesitamos establecer el límite superior del parámetro de tipo. Esto se implementa mediante una declaración de superclase heredada por todos los argumentos pasados entre corchetes angulares. Se verá así: class Pair . De esta manera, el compilador aprende que en lugar del parámetro T, puede sustituir la clase Number o una de sus subclases.

Esta es una técnica común. Tales restricciones se utilizan a menudo para asegurar la compatibilidad de los parámetros de tipo en la misma clase. Considere un ejemplo en nuestra clase Pair: class Pair . Aquí le decimos al compilador que el tipo T puede ser arbitrario y que el tipo V debe ser del tipo T o una de sus subclases.

La restricción "desde abajo" ocurre exactamente de la misma manera, pero en lugar de la palabra se extiende, la palabra super se escribe. Es decir, la declaración de clase Pair indica que en lugar de T, se puede sustituir una ArrayList o cualquier clase o interfaz que hereda.

Métodos y constructores genéricos de Java

En Java, las generalizaciones pueden aplicarse no sólo con respecto a las clases, sino también a los métodos. Por lo tanto, el método generalizado se puede declarar en la clase habitual.

Como se puede ver en la figura anterior, no hay nada complicado en la declaración del método generalizado. Es suficiente colocar los corchetes angulares antes del método del tipo de retorno y especificar los parámetros de tipo en ellos.

En el caso de un constructor, todo se hace de la misma manera:

Los soportes angulares en este caso se colocan delante del nombre del constructor, ya que no devuelve ningún valor. El resultado del trabajo de ambos programas será:

Entero

Cadena