instance :: class.java与instance.javaClass [英] instance::class.java vs. instance.javaClass

查看:74
本文介绍了instance :: class.java与instance.javaClass的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

吉文·科特林1.1.对于某个类的instanceinstance::class.javainstance.javaClass似乎几乎等效:

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较短,可以忽略不计,但instance::class.java与类型上的相应用法更一致.虽然可以在某些类型上使用.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

因此,我认为最好不要使用.javaClass以获得更好的一致性.有反对的说法吗?

So, I would argue that it is better to never use .javaClass for more consistency. Are there any arguments against that?

推荐答案

这两种构造的区别在于,对于静态(声明或推断)的表达式foo,类型为Foo:

The difference in these two constructs is that, for an expression foo of static (declared or inferred) type Foo:

  • foo.javaClass键入为Class<Foo>

foo::class.java键入为Class<out Foo>

实际上,后者更为精确,因为foo求值的实际值可以不是Foo本身的实例,而是其子类型之一的实例(正是协变量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).

正如@marstran在对该问题的评论中正确指出的那样,.javaClass曾经被视为已弃用(请参见

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)

请注意,Int.javaClass并不表示Int的类型,而是Int伴随对象的Java类.而Int::class.java是未绑定的类引用,表示类型.要使用.javaClass获取它,您需要在Int实例上调用它,例如1.javaClass.

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.

这是.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)
}

此示例使用kotlin-reflect.

这是因为someFooProperty表示Bar而不是Foo的属性,但是由于它是从someFoo.javaClass获得的(Class<Foo>然后转换为KClass<Foo>),因此编译器允许我们将其与in Foo投影.

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.

这篇关于instance :: class.java与instance.javaClass的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆