instance :: class.java与instance.javaClass
鉴于Kotlin 1.1。 对于某个类的instance
, instance::class.java
和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
来获得更好的一致性。 有什么反对的吗?
这两个构造的区别在于,对于静态(声明或推断)类型Foo
的表达式foo
:
-
foo.javaClass
类型为Class<Foo>
-
foo::class.java
类型为Class<out Foo>
事实上,后者更精确,因为foo
评估的实际价值可能不是Foo
本身的一个实例,而是它的一个子类型(这正是out Foo
的协变所表示的)。
正如@marstran在关于这个问题的评论中正确地指出的那样, .javaClass
曾经被认为是被弃用的(参见Kotlin 1.1 RC公告 ),因为它可以破坏类型安全(见下文),但是之后保持原样,因为它是广泛使用并用::class.java
的替代替换它将需要在代码中添加显式的未经检查的强制转换。
另请参阅此答案下的评论:( 链接)
请注意, Int.javaClass
不表示Int
的类型,而是Int
的伴随对象的Java类。 而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
投影中使用它。