不知道大家在使用Java的反射时,是怎样将一个随机的对象解析成Json的。
我的做法是:获取类中所有字段的名称,然后在跟 ‘set’ 或 ‘get’ 拼接起来,然后在使用 Method 的 invoke() 方法进行调用。
不过在kotlin中的属性,一般是没有java中的那些 'getter' 和 ‘setter’ 的。我们该通过何种方式来获取属性的值呢?
其实,要在Kotlin中获取属性的值比Java要更加便捷。看看下面这段代码val props=t::class.memberProperties
props.forEach {
println(it.call(t))
}
在这里通过使用类的字面量,可以获取到KClass对象。这里面保存了类似java中Class的内容。从中可以获取和这个对象或类相关的属性、成员函数、扩展函数、构造函数、静态属性等等信息。具体写法是这样的:val c = MyClass::class
注意:要想使用某个类的实例来获取类的字面量,则该实例对应的类型必须是nullable的。
这里我就不得不吐槽一下,kotlin中一点很蛋疼的地方。在Kotlin 明明默认Any作为Kotlin中所有类的基类,类似于Java中的Object。可是,为甚么在使用范型的时候,范型所对应的类型却不是Any的基类。 所以在我一开始想使用范型来实现的时候,编译器总是报下面这样的错:Error:(20, 19) Kotlin: Expression in a class literal has a nullable type 'T', use !! to make the type non-nullable
所以,如果想结合范型和反射机制的话,还是得使用java中的 Class对象才行。在kotlin中你可以通过以下代码获取到Java的Class对象:val clazz=T::class.java
好了,现在再让我们回过头来看看,之前代码中的 props 变量。他的类型是 Collection>。保存了,类实例中的属性的相关信息。我们可以从中获取到相应属性的值。只要使用下面这段代码:val propValue=prop.call(t) //t 持有该属性的类的实例。
所以最终,将一个简单的对象转换成Json字符串的代码是这样子的:object ObjectMapper { fun parse(t:Any):String{ val props=t::class.memberProperties
var jsonStr="{${t::class.simpleName}:{"
props.forEachIndexed { index, it ->
jsonStr+="\"${it.name}\":\"${it.call(t)}\""+if(index==props.size-1) "" else ","
}
jsonStr+="}}"
return jsonStr
}
}
注意:有人如果是刚学Kotlin的话,可能对上面代码中的 if...else 语句的用法感到有些奇怪:怎们直接和前面的字符串用加号连起来了呢?其实,再Kotlin中 if...else 是可以当作表达式来使用的,代替了Java中三元表达式。
使用:fun main(args: Array) { val json=ObjectMapper.parse(User("feint",11,"1231241"))
println(json)
}
User 类:class User(val name: String="",val age: Byte=0,val password:String="")
最后输出的结果是这样的:{User:{"age":"11","name":"feint","password":"1231241"}}
最后再说一点,通过反射机制获取的属性默认是只读的,也就是说你只能获取属性的值,而不能为属性赋值。总体感觉来说Kotlin的反射机制用起来还是没有Java的灵活性高,总是会被那些新添加的语言特性束缚住。