¿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); } } 
  • Invoque el método Java de Kotlin con parámetro de list
  • La variable de instancia de Kotlin es nula cuando se accede por la class proxied de Spring
  • Kapt, Kotlin, Dagger2 Error durante el process de anotación
  • Dagger 2 ContributesAndroidInjector proporciona actividad al module
  • Convierta ByteArrayOutputStream a json en Kotlin
  • Reflexión de kotlin para el método de Java que acepta una matriz de class nula
  • Gradle no puede resolver references de otro module
  • RxJava salida diferente entre Flowable y Observable con window y Groupby
  • ¿Cuál es la mejor manera de encontrar un elemento en las lists anidadas?
  • Enlace de datos: el campo Observable con valor lambda no comstack
  • El process de anotación de Kotlin ignora elementos con nombres similares