问题
I'm trying an example in kotlin, like:
fun test(){
val harfler = listOf("a","b",'c','d')
println(harfler.all {
it.javaClass == String::class.java || it.javaClass == Char::class.java
})
}
List contains Char or String but all function in this expression returns false,Why return false?
Can anybody explain it?
Edit for @JBNizet
回答1:
As @JB Nizet has already told you how to analyze the problem.
According to the Mapped Types, The Kotlin Char will be mapped to Java Type decide on its declaration.
- when declare as a non-nullable type
Charit is a primitive Java typechar. - when declare as a nullable type
Char?it is a Java wrapper typeCharacter. when declare as a type argument
List<Char>it is a Java wrapper typeCharacter.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 })
But I want to say that there is a different between the usage and the declaration.
For example, the parameter type it is a java.lang.Character, but its javaClass is char.
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'))
}
And the example below show the different as further, this is why I declare the array type to Array<Any> rather than Array<Char> in preceding example:
// 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 })
Why did the strange behavior occurs in Koltin?
This is because Kotlin Char and other wrapper classes represent 2 roles. one is a Java primitive type char, another is a Java wrapper class java.lang.Character. However, Kotlin Char is statically which means you can't change its type in runtime. and a Char should be mapped to a char by default in Kotlin.
IF you want get the wrapper type every time, you should use KClass.javaObjectType instead, for example:
// v--- char
println(Char::class.java)
// v--- java.lang.Character
println(Char::class.javaObjectType)
The Iterable#all operation is a short-circuiting operation, which means if any first element didn't satisfied will return false immediately.
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
}
When checking a Kotlin class like as Char and others. you should use the Kotlin type checking mechanism rather than traditional comparing approach, it helps you avoid such a confusion. for example:
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
So your code can replace with type checking as below:
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
}
来源:https://stackoverflow.com/questions/45397859/whats-the-behavior-of-iterableall-why-did-kotlin-charclass-java-char-ja