¿Por qué `como` en Kotlin no echó en este caso

¿Por qué Java imprime false en este caso?

Estoy comenzando a escribir Kotlin hoy, y quiero lanzar el parámetro con generics PERO el resultado es inesperado. Y no sé por qué?

 fun main(args: Array<String>) { var t = TEST<Int, String>() print(t.returns("12") is Int) // print false } @Suppress("UNCHECKED_CAST") class TEST<out T, in R> { fun returns(r: R): T { return r as T } } 

Lo siento, si mi inglés es malo.

Debido a la forma en que los generics funcionan en la JVM, esto ocurre porque ignora la advertencia dada por @Suppress("UNCHECKED_CAST") .

Simplemente coloque las comstackciones de la class TEST en la siguiente class de Java:

 class TEST { Object returns(Object r) { return r; } } 

Debido a que los generics no se reifican durante el time de ejecución, esto significa que los moldes con generics no tienen sentido.

Una forma de evitar esto es usar los generics reified de kotlin, una function en línea y una class anónima para forzar un lanzamiento real, en lugar de uno que se simplifique a Object :

 open class TEST<out T, in R> { open fun returns(r: R): T { return r as T } } inline fun <reified T, R> createTest(): TEST<T,R> { return object : TEST<T,R>() { override fun returns(r: R): T { return r as T } } } fun main(args: Array<String>) { var t = createTest<Int, String>() print(t.returns("12") is Int) // Causes classcastexception } 

Los generics de Java tienen borrado de tipo . Esto dificulta que los lenguajes JVM implementen generics reificados. Algunos lenguajes como Scala do, algunos idiomas como Kotlin no .

Este lanzamiento sin marcar está realmente desmarcado, de ahí la advertencia. Sin los generics reificados, no se puede hacer una comprobación adecuada, y el comstackdor solo realizará la comprobación de types en el límite del código genérico y no genérico, en time de ejecución. Debido a que su ejemplo realmente no tiene una parte no genérica, no se realiza tal comprobación de types. La expresión is no requiere que el lado izquierdo sea de ningún tipo específico, por lo que incluso la verificación del time de ejecución se omite, al igual que en Java.

Considere el siguiente ejemplo donde el valor de retorno se almacena en una variable:

 fun main(args: Array<String>) { var t = TEST<Int, String>() var k = t.returns("12") // runtime error here print(k is Int) } @Suppress("UNCHECKED_CAST") class TEST<out T, in R> { fun returns(r: R): T { return r as T } } ... Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number at MainKt.main(main.kt:3) 

Kotlin usa el verificador de types de Java en muchos lugares. Si considera el código Java equivalente, se comporta de la misma manera:

 public class JMain { public static void main(String[] args) { TEST<Integer, String> t = new TEST<>(); System.out.println(t.returns("12") instanceof Integer); // false } static class TEST<T, R> { @SuppressWarnings("unchecked") public T returns(R r) { return (T)r; } } } 

El resultado es false lugar de una ClassCastException porque los parameters generics Tipo Borrado se producen en time de compilation.

  • Reemplace todos los parameters de tipo en types generics con sus límites u Objeto si los parameters de tipo son ilimitados. El bytecode producido, por lo tanto, contiene solo classs, interfaces y methods ordinarios.
  • Insertar yesos tipo 'si es necesario para preservar la security del tipo.

Entonces, el código de arriba en su pregunta, el tipo de returns método de returns es Object vez de Integer . y una String se puede asignar a un Object incluso si no hay conversión adicional. para que compruebe una String ya sea una Int que siempre será false .

Otro caso es declarar una class con types de parameters acotados , que arrojará una ClassCastException . por ejemplo:

 @Suppress("UNCHECKED_CAST") class TEST<out T : Int, in R : String> { fun returns(r: R): T { return r as T } } fun main(args: Array<String>) { var t = TEST<Int, String>() print(t.returns("12") is Int) // ^--- throws ClassCastException } 

después del borrado de tipo de una class genérica con types de parameters acotados es el siguiente:

 public final class TEST{ public int returns(String value){ return ((Integer) value); } } 
  • Cómo crear el controller de respuesta genérica para el error y validar la respuesta utilizando retrofit, rxjava y dagger
  • ¿Insertar o agregar un elemento en ArrayList en Kotlin?
  • El parámetro de tipo Force es invariante en el sitio de uso cuando es covariante en el sitio de statement
  • Herencia de la interfaz: extiende una interfaz en Kotlin
  • ¿Dónde se aloja la antigua especificación de Kotlin?
  • Usando Kotlin en una biblioteca de Android distribuida como AAR
  • ¿Puede kotlin definir el método dynamic cuando la class init?
  • las proyecciones no están permitidas para los subtypes inmediatos de un supertipo
  • cómo especificar el order de plugin de comstackdor maven
  • Vista de Android get el contenido original "Ajustar contenido" de mi vista
  • Cómo manejar el event handling errores en un solo lugar en rxjava usando wrapper