最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

kotlin - Why is the Class<T> passed to a function always a String? - Stack Overflow

programmeradmin3浏览0评论

I'am trying to check an amount of specific type in list, by passing the data type to function, but it gets a wrong data type

fun <T> checkTypesOfElements(list: List<Any>, clazz: Class<T>): Unit {
     println(clazz.name::class.simpleName) // DataType for check
    list.forEach { println(it::class.simpleName) } // Check of DataTypes
    println(list.count { it::class == clazz.name::class }) // result
}

fun main() {
    val listOfObjects = listOf(51, "Hello", 42, "Kotlin", 123L)
    checkTypesOfElements(listOfObjects, Long::class.java)
}

But it outputs this:

String
Int
String
Int
String
Long
2

Why is the first line String and not Long?

I'am trying to check an amount of specific type in list, by passing the data type to function, but it gets a wrong data type

fun <T> checkTypesOfElements(list: List<Any>, clazz: Class<T>): Unit {
     println(clazz.name::class.simpleName) // DataType for check
    list.forEach { println(it::class.simpleName) } // Check of DataTypes
    println(list.count { it::class == clazz.name::class }) // result
}

fun main() {
    val listOfObjects = listOf(51, "Hello", 42, "Kotlin", 123L)
    checkTypesOfElements(listOfObjects, Long::class.java)
}

But it outputs this:

String
Int
String
Int
String
Long
2

Why is the first line String and not Long?

Share Improve this question asked Mar 17 at 10:40 Ацкий КонструкторАцкий Конструктор 111 silver badge1 bronze badge 1
  • 2 I'm not a Kotlin person, but it looks to me like you're printing out the simple name of the class of Class.getName(), which will always be string. Why don't you just use println(clazz.simpleName)? – Jon Skeet Commented Mar 17 at 10:44
Add a comment  | 

2 Answers 2

Reset to default 3

clazz.name is a String. Therefore clazz.name::class is always String::class, and the simpleName of String::class is of course String.

It seems like you have overcomplicated this. To print the simple name of clazz, just do

println(clazz.simpleName)

You made a similar mistake in the third line. It should be:

println(list.count { it::class.java == clazz })

This still will not count the number of Longs correctly, because the Class argument you passed in main refers to the class of the primitive Java type (long.class in Java), whereas the elements in the list are instances of java.lang.Long (Long.class in Java). You need to pass Long::class.javaObjectType instead:

checkTypesOfElements(listOfObjects, Long::class.javaObjectType)

If you use the Kotlin KClass instead of the Java Class, there will not be such complications. Here I have rewritten the method to take a KClass and return an Int.

fun checkTypesOfElements(list: List<Any>, clazz: KClass<*>) =
    list.count { it::class == clazz }

// usage:
println(checkTypesOfElements(listOfObjects, Long::class)) // prints 1

With clazz.name::class.simpleName you access the name property of the Class object, which is, well, the name - as a String, like "long". You then retrieve the class of the string "long" which is String.

What you really want to do is use the class itself:

println(clazz.simpleName)

This also applies to the actual comparison:

println(list.count { it::class == clazz })

Although this solves the issue with the Long being mistaken as a String, your comparison still won't work. The reason for that becomes more clear if you do not use simpleName. If you simply remove it, you get this output now:

long
class kotlin.Int
class kotlin.String
class kotlin.Int
class kotlin.String
class kotlin.Long
0

The class passed as a parameter seems to be somehow different than the class retrieved from the actual objects. In fact, the parameter is of type java.lang.Class where the class you retrieve from the objects is of type kotlin.reflect.KClass. After all, the parameter you pass to checkTypesOfElements is Long::class.java, a Kotlin class converted to a Java class.

To fix the mismatch you could also convert the object's class to a Java class, like this:

list.forEach { println(it::class.java) } // Check of DataTypes
println(list.count { it::class.java == clazz }) // result

Although this will work with most objects now (like String), it actually won't work for Long. From the output you can see that the parameter you pass is long, where the type of the actual object is class java.lang.Long:

long
class java.lang.Integer
class java.lang.String
class java.lang.Integer
class java.lang.String
class java.lang.Long
0

The reason is that the Java type system differentiates between the primitive type long and the object type Long. To circumvent this, you can switch away from Java types and move to Kotlin types, like this:

fun <T: Any> checkTypesOfElements(list: List<Any>, clazz: KClass<T>): Unit {
    println(clazz) // DataType for check
    list.forEach { println(it::class) } // Check of DataTypes
    println(list.count { it::class == clazz }) // result
}

fun main() {
    val listOfObjects = listOf(51, "Hello", 42, "Kotlin", 123L)
    checkTypesOfElements(listOfObjects, Long::class)
}

And this finally reproduces the expected output:

class kotlin.Long
class kotlin.Int
class kotlin.String
class kotlin.Int
class kotlin.String
class kotlin.Long
1
发布评论

评论列表(0)

  1. 暂无评论