• Skip to primary navigation
  • Skip to main content
  • Skip to footer

Codemotion Magazine

We code the future. Together

  • Discover
    • Events
    • Community
    • Partners
    • Become a partner
    • Hackathons
  • Magazine
    • DevOps
    • Carreras tech
    • Frontend
    • Inteligencia Artificial
    • Dev life
    • Desarrollo web
  • Talent
    • Discover Talent
    • Jobs
    • Manifiesto
  • Companies
  • For Business
    • EN
    • IT
    • ES
  • Sign in

Fabrizio Tedeschidiciembre 9, 2024 3 min read

Una limitación de los tipos genéricos en Java

Lenguajes de programación
java message modeling
facebooktwitterlinkedinreddit

Problema

Consideremos la siguiente clase Person y las clases hijas Manager y Employee, definidas de la siguiente manera:

public static class Person {
String name;
public Person(String name) { this.name = name; }
}

public static class Manager extends Person {
public Manager(String name) { super(name); }
}

public static class Employee extends Person {
public Employee(String name) { super(name); }
}

Supongamos ahora un método estático genérico que acepta dos parámetros de un tipo genérico T y devuelve un objeto de tipo T. Al tipo T se le aplica la restricción <T extends Person>, lo que significa que T debe tener AL MENOS todos los atributos y métodos definidos en la clase Person.

Recommended article
Code reviews, revisione del codice
mayo 26, 2025

Migrando a Drupal: una guía práctica

Dennis Torres Rodriguez

Lenguajes de programación

Supongamos el siguiente método estático definido de la siguiente forma:

public static T foo(T t1, T t2) {
// Hacer algo
return …;
}

Dadas las siguientes instancias p1 y p2, realizamos la siguiente invocación del método foo():

Employee p1 = new Employee("John");
Manager p2 = new Manager("Johanna");

Person out = foo(p1, p2);

El objetivo es imponer que ambos parámetros pasados al método foo() sean del mismo tipo, de forma que el compilador genere un error si no se cumple esta condición.

Observación

Al ejecutar la invocación del método anterior, NO se genera ningún error de compilación, ya que tanto p1 (de tipo Employee) como p2 (de tipo Manager) cumplen con la restricción impuesta al tipo genérico T. Esto se debe a que ambas clases heredan los atributos de la clase Person.

Para entender mejor este comportamiento, es necesario analizar los mecanismos de compilación y precompilación del código.

El rol del type erasure

El type erasure es el mecanismo de precompilación que reemplaza todos los tipos genéricos por el tipo de objeto con mayor compatibilidad, respetando las restricciones impuestas.

En este caso, como se establece la restricción <T extends Person>, el tipo genérico T será reemplazado por la clase que proporcione la mejor compatibilidad y cumpla con las restricciones impuestas. El código resultante será:

public static Person foo(Person t1, Person t2) {
// Hacer algo
return …;
}

Por lo tanto, se hace evidente que, cuando se realiza la invocación mencionada anteriormente, tanto p1 como p2 son aceptados por el compilador, ya que ambos son «descendientes» de Person.


El rol del type inference

Cuando se pasan como parámetros de foo() instancias de objetos del mismo tipo, entra en juego el mecanismo de type inference, que determina qué clase utilizar durante la compilación.

  • Si se pasan instancias de dos objetos del mismo tipo, la clase de compilación será la subclase de las instancias pasadas como argumentos.
  • Si se pasan instancias de dos objetos de diferentes subclases de Person, el compilador seleccionará la clase común superior, que en este caso es Person.

Ejemplo:

  • Si se pasan dos objetos de tipo Employee, la clase de compilación será Employee.
  • Si se pasan un Employee y un Manager, la clase de compilación será Person, ya que es la clase común superior.

Problema identificado

El problema principal de los tipos genéricos es que, cuando se pasan a un método dos instancias de tipo genérico T limitado con la sintaxis <T extends C>, si las instancias pasadas como parámetros son subclases de C, no es posible generar errores de compilación si los parámetros tienen tipos diferentes.


Posibles soluciones al problema

Solución alternativa 1: Clase auxiliar

Si se conoce de antemano el número de parámetros del mismo tipo que se pasarán al método, se puede definir una clase con tipo genérico que acepte los objetos y luego pasar esta clase como un único parámetro al método foo().

Implementación

<code>// Clase auxiliar con dos objetos del mismo tipo
public static class Pair<P> {
    private P first;
    private P second;

    public Pair(P first, P second) {
        this.first = first;
        this.second = second;
    }

    public P getFirst() {
        return first;
    }

    public P getSecond() {
        return second;
    }
}

// Nueva definición de foo()
public static <T extends Person> T foo(Pair<T> pair) {
    // Hacer algo
    return ...;
}</code>

Employee p1 = new Employee("John");
Employee p2 = new Employee("Francis");
Manager p3 = new Manager("Johanna");

// Aceptado
Pair<Employee> pair = new Pair<>(p1, p2);
Person out = foo(pair);

// Error de compilación (p1 es Employee y p3 es Manager)
Pair<Employee> pair2 = new Pair<>(p1, p3);
Person out = foo(pair2);Lenguaje del código: PHP (php)

Explicación
En esta solución:

  • La clase Pair garantiza que ambos parámetros first y second sean del mismo tipo.
  • Como foo acepta un parámetro de tipo Pair<T>, si se intenta crear un Pair<Employee> con un Employee y un Manager, se generará un error de compilación.

Solución alternativa 2: Verificación en tiempo de ejecución

Otra posible solución es realizar una verificación en runtime para asegurarse de que los dos parámetros pasados al método foo() sean del mismo tipo. Para esto, se puede utilizar el método getClass() para comparar las clases de los parámetros.

Implementación

public static <T extends Person> T my_method(T t1, T t2) {
if (t1.getClass() != t2.getClass()) {
throw new IllegalArgumentException("Los argumentos son de tipos diferentes");
}

// Hacer algo
return ...;
}

Artículos relacionados

¿Por qué Drupal sigue siendo relevante en 2025?

Dennis Torres Rodriguez
mayo 26, 2025

Primeros pasos con Drupal: conceptos clave y arquitectura base

Dennis Torres Rodriguez
mayo 26, 2025

10 Consejos a la hora de crear tus apps iOS

Javier
mayo 26, 2025

¿Realmente necesitas esa Nueva Tecnología o solo quieres usarla?

srjonro
marzo 5, 2025
Share on:facebooktwitterlinkedinreddit

Tags:Java

Fabrizio Tedeschi
¿Founder Mode vs Manager Mode: cuál es tu estilo?
Artículo anterior
Autocrítica vs Síndrome del Impostor: cómo identificar, diferenciar y luchar contra ello.
Próximo artículo

Footer

Discover

  • Events
  • Community
  • Partners
  • Become a partner
  • Hackathons

Magazine

  • Tech articles

Talent

  • Discover talent
  • Jobs

Companies

  • Discover companies

For Business

  • Codemotion for companies

About

  • About us
  • Become a contributor
  • Work with us
  • Contact us

Follow Us

© Copyright Codemotion srl Via Marsala, 29/H, 00185 Roma P.IVA 12392791005 | Privacy policy | Terms and conditions