2017-10-10 32 views
8

Given Kotlin 1.1。對於一些類的instanceinstance::class.javainstance.javaClass似乎是等效的:instance :: class.java vs. instance.javaClass

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

有細微的差別,但是:

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

instance.javaClass是可以忽略不計短,但instance::class.java與較爲一致相應的使用類型。雖然你可以在某些類型的使用.javaClass,結果可能不是你所期望的:

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 

所以,我認爲這是更好地從不使用.javaClass更多的一致性。有什麼反對的嗎?

+1

我想我已經讀過'javaClass'被認爲已被棄用,但我現在找不到它。 – marstran

回答

8

在這兩個構建體中的不同之處在於,對於靜態的表達foo(聲明或推斷)類型Foo

  • foo.javaClass的類型爲Class<Foo>

  • foo::class.java的類型爲Class<out Foo>

實際上,後者是m因爲foo評估的實際值可能不是Foo本身的一個實例,而是它的一個子類型(並且它正是由協變子out Foo表示的)。

由於@marstran在該問題的評論中正確指出,.javaClass曾被認爲不推薦使用(請參閱Kotlin 1.1 RC announcement),因爲它可以打破類型安全性(見下文),但之後保持原樣,因爲它是廣泛使用並用::class.java替代它將需要在代碼中添加明確的未經檢查的強制轉換。

而且,看到評論這個答案下:(link)


請注意:Int.javaClass不表示的Int類型,而是是Java類Int的同伴對象。而Int::class.java是未綁定的類引用,並表示類型。要獲得.javaClass,您需要在Int實例上調用它,例如, 1.javaClass


這裏有究竟如何.javaClass可以打破類型安全。此代碼編譯,但符在運行時:

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

本例使用kotlin-reflect

這是因爲someFooProperty表示Bar,不Foo一個屬性,但因爲它是從someFoo.javaClass獲得(Class<Foo>然後轉換爲KClass<Foo>)編譯器允許我們與in Foo投影使用。

相關問題