Iterable#all 的行为是什么以及为什么 Kotlin Char::class.java != char.javaClass

What's the behavior of Iterable#all & Why did Kotlin Char::class.java != char.javaClass

我正在尝试使用 kotlin 的示例,例如:

fun test(){    
    val harfler = listOf("a","b",'c','d')
    println(harfler.all { 
           it.javaClass == String::class.java || it.javaClass == Char::class.java 
    })
}

列表包含 CharStringall 函数在此表达式 returns false,为什么 return false

谁能解释一下?

编辑 对于@JBNizet

正如@JB Nizet 已经告诉你如何分析问题。

根据 Mapped Types,Kotlin Char 将映射到 Java 类型决定其声明。

  • 当声明为 不可空 类型时 Char 它是原始 Java 类型 char.
  • 当声明为 nullable 类型时 Char? 它是 Java 包装类型 Character.
  • 当声明为 类型参数时 List<Char> 它是 Java 包装类型 Character.

    val it = 'a'
    //                v--- it should be `Any`
    val array: Array<Any> = arrayOf('a')
    
    //          v--- char
    println(it.javaClass)
    
    //             v--- print [java.lang.Character]  
    println(array.map { it.javaClass })
    

但是我想说用法声明是有区别的。 比如参数类型it是一个java.lang.Character,但是它的javaClasschar.

fun typeOf(it: Char?) = it?.javaClass

fun test() {
    //                                          v--- java.lang.Character
    println(::typeOf.javaMethod!!.parameterTypes[0])
    //       v--- but it return `char` rather than `java.lang.Character`
    println(typeOf('a'))
}

而下面的例子进一步显示了不同,这就是为什么我在前面的例子中将数组类型声明为 Array<Any> 而不是 Array<Char> 的原因:

//                v--- uses `java.lang.Character` instead
val array: Array<Char> = arrayOf('a')

//                       v--- java.lang.Character
println(array.javaClass.componentType)
//             v--- [char]
println(array.map { it.javaClass })

为什么 Koltin 会出现奇怪的行为?

这是因为 Kotlin Char 和其他包装器 classes 代表了 2 个角色。一个是 Java 原始类型 char,另一个是 Java wrapper class java.lang.Character。然而,Kotlin Charstatically 这意味着你不能在运行时改变它的类型。在 Kotlin 中,默认情况下 Char 应该映射到 char

如果你想每次都获取包装类型,你应该使用KClass.javaObjectType代替,例如:

//                  v--- char 
println(Char::class.java)
//                  v--- java.lang.Character
println(Char::class.javaObjectType)

Iterable#all操作是一个短路操作,这意味着如果任何第一个元素不满足将立即return false

inline fun <T> Iterable<T>.all(predicate: (T) -> Boolean): Boolean {
    //   return `false` immediately the condition didn't satisfied
    //                        v                                            
    for (element in this) if (!predicate(element)) return false
    return true
}

检查 Kotlin class 时,如 Char 和其他。你应该使用 Kotlin type checking 机制而不是传统的比较方法,它可以帮助你避免这种混淆。例如:

val anything: Array<Any> = arrayOf('a')
val chars: Array<Char> = arrayOf('a')

println(chars.all { it is Char }) // print true
println(anything.all { it is Char }) // print true

因此您的代码可以替换为 type checking,如下所示:

fun test() {
    val harfler = listOf("a", "b", 'c', 'd')

    //                       v---------------v--- use type checking here 
    println(harfler.all { it is String || it is Char }) // print true
}