instance :: class.java与instance.javaClass [英] instance::class.java vs. instance.javaClass
问题描述
吉文·科特林1.1.对于某个类的instance
,instance::class.java
和instance.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屋!