主要是通过反射实现,对比两个对象之中相同属性名的值是否一致,然后按照既定规则进行赋值,或者不处理。
如果有更复杂的交互逻辑,可以根据这中代码能力进行拓展。
通用方法代码
/**
* [to] 把取的值尝试放到这里
* [emptyReplacement] 如果取的值是空的,是否也需要替换,默认不需要
*
* use : 需要取值的对象.propertyTo(需要把值放入的对象,空值是否也需要替换)
*
*/
fun Any?.propertyTo(to: Any?, emptyReplacement: Boolean = false) {
val from = this
if (from == null || to == null) return
propertyToChildren(from, to, emptyReplacement)
}
/**
* 属性替换方法
* [sFromFields] 取值对象的所有私有属性
* [rf] 原取值对象
* [rt] 原设置对象
* [sTo] 当前设置对象(可能是原设置对象的父类,或者自己)
*/
private fun valueExChange(sFromFields: Array<Field>, rf: Any, rt: Any, sTo: Class<*>, emptyReplacement: Boolean = false) {
try {
for (field in sFromFields) {
field.isAccessible = true
val value: Any? = field.get(rf)
if (emptyReplacement || (null != value && "" != value)) {
try {
val toField: Field = sTo.getDeclaredField(field.name)
if (field.type.toString() == toField.type.toString()) {
toField.isAccessible = true
val toValue = toField.get(rt)
if (toValue != value) {
toField.set(rt, value)
}
}
} catch (e: NoSuchFieldException) {
// 这里是找不到这个property,不用管
}
}
}
} catch (ignored: Exception) {
}
}
/**
* 对当前类进行属性转换
*/
private fun propertyToChildren(from: Any, to: Any, emptyReplacement: Boolean = false) {
val fields: Array<Field> = from.javaClass.declaredFields
valueExChange(fields, from, to, to.javaClass, emptyReplacement)
looperParent(from, to, from.javaClass, to.javaClass, emptyReplacement)
}
/**
* 递归转换当前类的各级父类
*/
private fun looperParent(rf: Any, rt: Any, from: Class<*>?, to: Class<*>?, emptyReplacement: Boolean = false) {
if (from == null || to == null) return
if (from.superclass != null && to.superclass != null
&& "class java.lang.Object" != from.superclass.toString()
&& "class java.lang.Object" != to.superclass.toString()
) {
val sFrom = Class.forName((from.superclass as Class).name)
val sFromFields = sFrom.declaredFields
val sTo = Class.forName((to.superclass as Class).name)
valueExChange(sFromFields, rf, rt, sTo, emptyReplacement)
looperParent(rf, rt, sFrom, sTo, emptyReplacement)
}
}
测试代码
object TestDiff {
@JvmStatic
fun main(args: Array<String>) {
val old = TestEntity(
"这是旧的", 1,false,1L,1F,1.0, listOf(TestChildrenArrayEntity("旧的", "旧内容")),mutableListOf(TestChildrenArrayEntity("旧的", "旧内容")),
TestChildrenEntity("旧标题", "旧文本")
)
print("旧数据是:")
print(old)
print("\n\n")
val new = TestEntity2(
"", 2, true, 2L, 2F, 2.0, null, mutableListOf(TestChildrenArrayEntity("新的", "新内容")),
TestChildrenEntity("新标题", "新文本")
)
print("新数据是:")
print(new)
print("\n\n")
print("开始对比替换:\n")
new.propertyTo(old, true)
print("结束!\n")
print("旧数据:")
print(old)
print("\n新数据:")
print(new)
}
}
data class TestEntity(
val string: String?,
val int: Int,
val boolean: Boolean,
val long : Long,
val float: Float,
val double: Double,
val list: List<TestChildrenArrayEntity>?,
val mutableList: MutableList<TestChildrenArrayEntity>?,
val entity: TestChildrenEntity?
)
data class TestEntity2(
val strings: String?,
val ints: Int,
val booleans: Boolean,
val long : Long,
val float: Float,
val double: Double,
val list: List<TestChildrenArrayEntity>?,
val mutableList: MutableList<TestChildrenArrayEntity>?,
val entity: TestChildrenEntity?
)
data class TestChildrenEntity(val title: String, val content: String)
data class TestChildrenArrayEntity(val title: String, val content: String)
执行日志输出
旧数据是:TestEntity(string=这是旧的, int=1, boolean=false, long=1, float=1.0, double=1.0, list=[TestChildrenArrayEntity(title=旧的, content=旧内容)], mutableList=[TestChildrenArrayEntity(title=旧的, content=旧内容)], entity=TestChildrenEntity(title=旧标题, content=旧文本))
新数据是:TestEntity2(strings=, ints=2, booleans=true, long=2, float=2.0, double=2.0, list=null, mutableList=[TestChildrenArrayEntity(title=新的, content=新内容)], entity=TestChildrenEntity(title=新标题, content=新文本))
开始对比替换:
结束!
旧数据:TestEntity(string=这是旧的, int=1, boolean=false, long=2, float=2.0, double=2.0, list=null, mutableList=[TestChildrenArrayEntity(title=新的, content=新内容)], entity=TestChildrenEntity(title=新标题, content=新文本))
新数据:TestEntity2(strings=, ints=2, booleans=true, long=2, float=2.0, double=2.0, list=null, mutableList=[TestChildrenArrayEntity(title=新的, content=新内容)], entity=TestChildrenEntity(title=新标题, content=新文本))
Process finished with exit code 0