instance::class.java vs. instance.javaClass

后端 未结 1 1308
一个人的身影
一个人的身影 2020-12-30 23:20

Given Kotlin 1.1. For an instance of some class, instance::class.java and instance.javaClass seem to be nearly equivalent:

<         


        
相关标签:
1条回答
  • 2020-12-30 23:43

    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.

    0 讨论(0)
提交回复
热议问题