ProgramaciónDesarrollador Senior de Kotlin

¿Cómo funciona la palabra clave 'super' en Kotlin y en qué se diferencia de su uso en Java? ¿En qué casos surgirán dificultades de ambigüedad al implementar múltiples interfaces y cómo resolverlas?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

En Kotlin, la palabra clave super se utiliza para referirse a la implementación de un método o propiedad de la superclase o de la interfaz implementada. A diferencia de Java, Kotlin permite especificar explícitamente a través de qué interfaz o clase se debe invocar la implementación del método, lo que es especialmente importante en caso de "conflicto" entre múltiples interfaces con métodos idénticos.

Particularidad: Si una clase implementa múltiples interfaces en las que se define un método con la misma firma y hay una implementación predeterminada, es necesario especificar explícitamente qué implementación usar.

Ejemplo:

interface A { fun foo() = println("A") } interface B { fun foo() = println("B") } class C : A, B { override fun foo() { super<A>.foo() // Llamamos explícitamente a A.foo super<B>.foo() // Llamamos explícitamente a B.foo } }

Esto no se admite directamente en Java (Java no permite que las interfaces tengan campos/implementaciones de métodos hasta Java 8, e incluso en Java 8, los mecanismos son diferentes).

Pregunta engañosa

"¿Se puede en Kotlin referir a la implementación del método de la superclase a través de múltiples niveles de herencia?"

  • Error común: pensar que se puede referir a la implementación a través de una clase intermedia: super<Intermediate>.foo(), pero no es así: solo se puede referir a la superclase inmediata o a la interfaz que implementa directamente dicho método.

Ejemplo:

open class Base { open fun foo() = println("Base") } open class Mid : Base() { override fun foo() { println("Mid"); super.foo() } } class Child: Mid() { override fun foo() { super.foo() // llamará a Mid.foo() // super<Base>.foo() — error de compilación } }

Ejemplos de errores reales por desconocer los matices del tema


Historia

En un gran proyecto, las interfaces Logger y Auditor ambas definieron el método record(). Al implementar la clase que hereda ambas interfaces, el programador no sobrescribió explícitamente record(), resultando en un error de compilación "La clase debe sobrescribir la función pública abierta record()". Tuvo que implementar el método manualmente y delegar explícitamente en la interfaz correspondiente.


Historia

Al intentar invocar el método implementado de la superclase a través de múltiples capas intermedias (por ejemplo, super<Base>.foo()), se produjo un error de compilación. El desarrollador no conocía las limitaciones de Kotlin y no podía entender por qué la llamada directa no era posible.


Historia

Después de la actualización de la API, una de las interfaces añadió una implementación de función predeterminada que coincidía con otra interfaz. El código antiguo dejó de compilarse debido a un conflicto de implementaciones, y se tuvo que resolver el conflicto explícitamente implementando el método uno mismo y eligiendo qué implementaciones de las superinterfaces invocar internamente.