Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

145
Vistas
¿Cómo devolver la interfaz de la clase genérica que implementa la interfaz?

Quiero crear un método que acepte cualquier clase T que implemente cualquier interfaz I

Luego haga algo con la clase y devuelva la interfaz I que está implementada.

Esto es lo que he intentado:

 class MyLibrary { public static <I, T extends I> I registerImplementation(Class<T> classImpl) { I interfaceImpl = (I) classImpl.newInstance(); return interfaceImpl; } }

Luego estoy creando una interfaz y una clase que implementa esa interfaz:

 interface UserInterface { void doSomethingDefined(); } class UserClass_v1_10_R2 implements UserInterface { @Override public void doSomethingDefined() { System.out.println("What this does is well-defined"); } public void doVersionSpecificStuff() { System.out.println("This is not in the interface, so don't really depend on this"); } }

Sin embargo, cuando llamo al método que hace referencia UserClass , devuelve el mismo tipo de clase T en lugar del tipo de interfaz I , lo que permite llamar a todos los métodos de clase que no están declarados en la interfaz.

Es decir, en la siguiente declaración, aunque se declara registerImplementation() para devolver una referencia a UserInterface , el compilador ve la referencia como apuntando a una instancia de UserClass_v1_10_R2 , lo que permite el acceso a los métodos de implementación que no están en la interfaz.

 MyLibrary.registerImplementation(UserClass_v1_10_R2.class).doVersionSpecificStuff();

Contraste esto con el supuestamente idéntico

 UserInterface uiObj = MyLibrary.registerImplementation(UserClass_v1_10_R2.class); uiObj.doVersionSpecificStuff(); // This does not compile
over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Así es como el compilador infiere el tipo. Si compila con un indicador especial (no documentado):

 javac --debug=verboseResolution=all ...

verás que:

 Note: Deferred instantiation of method <I,T>registerImplementation(Class<T>) MyLibrary.registerImplementation(UserClass_v1_10_R2.class).doVersionSpecificStuff(); ^ instantiated signature: (Class<UserClass_v1_10_R2>)UserClass_v1_10_R2

Mire la firma instanciada: (Class<UserClass_v1_10_R2>)UserClass_v1_10_R2

Entonces necesita agregar otro argumento, para tomar la interfaz:

 public static <I, T extends I> I registerImplementation(Class<I> interfaceClass, Class<T> implClass) { // do whatever checks you want if this is an interface or if a constructor can be called.... I interfaceImpl = null; try { interfaceImpl = interfaceClass.cast(implClass.newInstance()); } catch (Exception e) { e.printStackTrace(); } return interfaceImpl; }

Por supuesto, esto plantea la pregunta si tiene múltiples interfaces, pero eso es algo en lo que debe pensar.

over 4 years ago · Santiago Trujillo Denunciar

0

Es posible lograr esto pasando la clase de interfaz deseada como otro argumento del método. Esto también permite verificar que la clase de tipo genérico es una interfaz, así como agregar controles adicionales para asegurarse de que se pueda crear una instancia de la clase que implementa la interfaz.

 public class MyLibrary { public static <I> I registerImplementation(Class<I> interfaceClass, Class<? extends I> implClass) { if (!interfaceClass.isInterface()) { throw new IllegalArgumentException("Must be an interface class"); } // Check constructor accessibility, etc... if (Modifier.isAbstract(implClass.getModifiers())) { throw new IllegalArgumentException("Must be instantiable"); } return implClass.newInstance(); } }

Esto devuelve una implementación de la interfaz pasada como primer parámetro. El tipo acotado del segundo parámetro Class<? extends I> significa que no se requiere una conversión explícita:

 // This returns UserInterface MyLibrary.registerImplementation(UserInterface.class, UserClass_v1_10_R2.class);
over 4 years ago · Santiago Trujillo Denunciar

0

El motivo de la discrepancia es que en la primera llamada al método genérico confía en la inferencia de tipos y los argumentos de tipo se infieren como I=UserClass_v1_10_R2 y T=UserClass_v1_10_R2 porque el compilador no tiene forma de determinar que I ser invocado como UserInterface de usuario.

Si invoca los parámetros de tipo explícitamente, el comportamiento será el esperado, es decir, un error de compilación:

 MyLibrary.<UserInterface, UserClass_v1_10_R2>registerImplementation( UserClass_v1_10_R2.class).doVersionSpecificStuff();

Cuando usa una variable local, no es completamente equivalente, porque la inferencia de tipo usa la información de tipo en la declaración de tipo de la variable local, que proporciona suficiente información al compilador para invocar el tipo I=UserInterface deseado.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda