instance :: class.java与instance.javaClass

鉴于Kotlin 1.1。 对于某个类的instanceinstance::class.javainstance.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.javaClassClass<Foo>然后转换为KClass<Foo> )获得的,所以编译器允许我们in Foo投影中使用它。