Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

148
Visualizações
¿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 Respostas
Responde à pergunta

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 Relatório

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda