Given Kotlin 1.1. For an instance
of some class, instance::class.java
and instance.javaClass
seem to be nearly equivalent:
val i = 0
println(i::class.java) // int
println(i.javaClass) // int
println(i::class.java === i.javaClass) // true
There is a subtle difference, however:
val c1: Class<out Int> = i::class.java
val c2: Class<Int> = i.javaClass
instance.javaClass
is negligibly shorter, but instance::class.java
is more consistent with the corresponding usage on a type. While you can use .javaClass
on some types, the result may not be what you would 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 argue that it is better to never use .javaClass
for more consistency. Are there any arguments against that?
An instance of a class is an object. It is also known as a class object or class instance. As such, instantiation may be referred to as construction. Whenever values vary from one object to another, they are called instance variables. These variables are specific to a particular instance.
A class is a blueprint which you use to create objects. An object is an instance of a class - it's a concrete 'thing' that you made using a specific class. So, 'object' and 'instance' are the same thing, but the word 'instance' indicates the relationship of an object to its class.
What is instance variable in Java? Instance variables in Java are non-static variables which are defined in a class outside any method, constructor or a block. Each instantiated object of the class has a separate copy or instance of that variable. An instance variable belongs to a class.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With