instancia :: class.java vs. instance.javaClass

Dado Kotlin 1.1. Para una instance de alguna class, instance::class.java y instance.javaClass parecen ser casi equivalentes:

 val i = 0 println(i::class.java) // int println(i.javaClass) // int println(i::class.java === i.javaClass) // true 

Sin embargo, hay una diferencia sutil:

 val c1: Class<out Int> = i::class.java val c2: Class<Int> = i.javaClass 

instance.javaClass es insignificantemente más corto, pero instance::class.java es más consistente con el uso correspondiente en un tipo. Si bien puede usar .javaClass en algunos types, el resultado puede no ser el esperado.

 println(i::class.java === Int::class.java) // true println(i.javaClass === Int.javaClass) // false println(Int::class.java === Int.javaClass) // false println(Int.javaClass) // class kotlin.jvm.internal.IntCompanionObject 

Entonces, yo diría que es mejor nunca usar .javaClass para más consistencia. ¿Hay algún argumento en contra de eso?

La diferencia en estos dos constructos es que, para una expresión foo de tipo estático (declarado o inferido), Foo :

  • foo.javaClass se escribe como Class<Foo>

  • foo::class.java se escribe como Class<out Foo>

De hecho, este último es más preciso, porque el valor real que evalúa foo puede ser una instancia de no Foo sino uno de sus subtypes (y es exactamente lo que denota la covariante out Foo ).

Como @marstran señaló correctamente en el comentario sobre la pregunta, .javaClass una vez se consideró obsoleto (ver el anuncio de Kotlin 1.1 RC ) porque puede romper la security del tipo (ver más abajo), pero luego se dejó tal cual porque era ampliamente utilizado y reemplazándolo con la alternativa de ::class.java requeriría agregar moldes explícitos no verificados en el código.

Además, vea los comentarios en esta respuesta: (enlace)


Tenga en count que Int.javaClass no denota el tipo de Int sino que es la class Java del object complementario del Int . Mientras que Int::class.java es una reference de class Int::class.java y denota el tipo. Para getlo con .javaClass , debe llamarlo a una instancia Int , por ejemplo, 1.javaClass .


Así es como exactamente .javaClass puede romper la security del tipo. Este código se comstack pero se rompe en time de ejecución:

 open class Foo class Bar : Foo() { val baz: Int = 0 } fun main(args: Array<String>) { val someFoo: Foo = Bar() val anotherFoo: Foo = Foo() val someFooProperty: KProperty1<in Foo, *> = // 'in Foo' is bad someFoo.javaClass.kotlin.memberProperties.first() val someValue = someFooProperty.get(anotherFoo) } 

Este ejemplo usa kotlin-reflect .

Eso es porque someFooProperty representa una propiedad de Bar , no de Foo , pero como se obtuvo de someFoo.javaClass ( Class<Foo> luego se convirtió en KClass<Foo> ) el comstackdor nos permite usarlo con la proyección in Foo .

  • ¿Cómo establecer el valor de propiedad delegada por reflexión en kotlin?
  • ¿Cómo uso el object Kotlin por reflexión?
  • Kotlin: ¿Es aquí una forma inteligente de lanzar NotImplementedError para todos los methods de una class?
  • por qué SomeClass :: class es KClass <SomeClass> pero esta :: class es KClass <out SomeClass>
  • ¿Cómo get los nombres de los parameters a través de la reflexión en kotlin?
  • La delegación de propiedad kotlin alias lanza Exception
  • ¿El comstackdor de Kotlin siempre conserva los nombres de los parameters en bytecode?
  • ¿Cómo get un KType en Kotlin?
  • ¿Cómo get una KClass de Array?
  • Reflexión de Kotlin: compruebe si la propiedad tiene tipo
  • Verificar si la function es extensión