Instance :: class.java vs. instance.javaClass

Given Kotlin 1.1. For instance some class, instance::class.java and instance.javaClass seem almost equivalent:

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

However, there is a subtle difference:

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

instance.javaClass negligible, but instance::class.java more consistent with the corresponding use for the type. Although you can use .javaClass for some types, the result may not be what you expect:

 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 

So, I would say it is better to never use .javaClass for more consistency. Are there any arguments against this?

+8
reflection kotlin
source share
1 answer

The difference in these two constructs is that for the expression foo static (declared or supposed) type foo :

  • foo.javaClass is introduced as Class<Foo>

  • foo::class.java is introduced as Class<out Foo>

In fact, the latter is more accurate, because the actual value that foo evaluates may not be an instance of foo itself, but one of its subtypes (and this is exactly what is denoted by the covariant out Foo ).

As @marstran correctly noted in the commentary on the question, .javaClass once considered deprecated (see Kotlin 1.1 RC declaration ), since it could violate type safety (see below), but later it remained as it is because it was widely used and replaced it with an alternative ::class.java , would require the addition of explicit unchecked throws to the code.

Also see comments on this answer: (link)


Note that Int.javaClass does not denote an Int type, but instead is a Java class of an Int companion object. While Int::class.java is a reference to an unrelated class and denotes a type. To get it using .javaClass , you need to call it on an Int instance, for example. 1.javaClass .


This is how .javaClass can violate type safety. This code compiles but breaks at runtime:

 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) } 

This example uses kotlin-reflect .

This is because someFooProperty represents the Bar property, not foo , but since it was obtained from someFoo.javaClass ( Class<Foo> and then converted to KClass<Foo> ), the compiler allows us to use it with an in Foo projection.

+8
source share

All Articles