Given Kotlin 1.1. For an instance
of some class, instance::class.java
and instance.javaClass
seem to be nearly equivalent:
<
The difference in these two constructs is that, for an expression foo
of static (declared or inferred) type Foo
:
foo.javaClass
is typed as Class<Foo>
foo::class.java
is typed as Class<out Foo>
In fact, the latter is more precise, because the actual value that foo
evaluates to can be an instance of not Foo
itself but one of its subtypes (and it's exactly what's denoted by the covariant out Foo
).
As @marstran correctly noted in the comment on the question, .javaClass
once was considered to be deprecated (see the Kotlin 1.1 RC announcement) because it can break type safety (see below), but it was afterwards left as-is because it was widely used and replacing it with the alternative of ::class.java
would require adding explicit unchecked casts in the code.
Also, see the comments under this answer: (link)
Please note that Int.javaClass
does not denote the type of Int
but instead is the Java class of the Int
's companion object. Whereas Int::class.java
is an unbound class reference and denotes the type. To get it with .javaClass
, you need to call it on an Int
instance, e.g. 1.javaClass
.
Here's how exactly .javaClass
can break 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
.
That's because someFooProperty
represents a property of Bar
, not Foo
, but since it was obtained from someFoo.javaClass
(Class<Foo>
then converted to KClass<Foo>
) the compiler allows us to use it with the in Foo
projection.