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 get una KClass de Array?
  • ¿Cómo puedo establecer una propiedad de un object complementario en Kotlin a través de la reflexión?
  • Los literales de class Kotlin con el lado izquierdo vacío aún no son compatibles.
  • Cómo acceder a los objects-miembros de una statement de object en kotlin
  • ¿Cómo puedo get una reference a un object Kotlin por su nombre?
  • Kotlin comtesting si la function requiere parámetro de instancia
  • Determinar si una instancia es una instancia de una class de datos
  • Kotlin obtiene la anotación de campo siempre vacía
  • por qué SomeClass :: class es KClass <SomeClass> pero esta :: class es KClass <out SomeClass>
  • ¿El comstackdor de Kotlin siempre conserva los nombres de los parameters en bytecode?
  • Kotlin enlazó la incoinheritance de las references invocables