前言
基于Kotlin的擴(kuò)展函數(shù)的特性,我們能很容易封裝一個(gè)全局的函數(shù)來實(shí)現(xiàn)某些功能
如全局的UI線程回調(diào)函數(shù)狼速,不管在代碼的任何地方娘扩,都可以讓指定代碼塊運(yùn)行到UI線程上
這次就分享一個(gè)深拷貝的擴(kuò)展函數(shù)
思路就是通過反射創(chuàng)建一個(gè)新的實(shí)例肺素,然后讀出要拷貝的對象每一個(gè)屬性的值再重新懟回去
具體可以看代碼是怎么實(shí)現(xiàn)的
/深拷貝
fun <T: Any> T.deepCopy(): T {
val copiedObjects = mutableMapOf<Any,Any>()
var initialObject = getValueFromCopiedCollection(this,copiedObjects)
initialObject = deepCopy(this, copiedObjects)
return initialObject
}
private fun<T: Any> deepCopy(obj: T,copiedObjects: MutableMap<Any,Any>): T{
val objClassJava = obj::class.java
val objClass = obj::class
// 基本數(shù)據(jù)類型直接返回
if (objClassJava.isPrimitive) {
return obj
} else {
if (objClass.javaPrimitiveType != null) {
return obj
}
}
when(obj){
is String -> {
val newString = String(obj.toCharArray())
copiedObjects[obj] = newString
return newString as T
}
is Array<*> -> {
val arrList = ArrayList<Any?>()
val newArray: Any
for (elem in obj){
if (elem == null)
arrList.add(elem)
else
arrList.add(getValueFromCopiedCollection(elem, copiedObjects))
}
newArray = obj.clone()
arrList.toArray(newArray)
copiedObjects[obj] = newArray
return newArray as T
}
is List<*> -> {
val arrList = ArrayList<Any?>()
for (elem in obj){
if (elem == null)
arrList.add(elem)
else
arrList.add(getValueFromCopiedCollection(elem, copiedObjects))
copiedObjects[obj] = arrList
}
}
is Map<*,*> -> {
val newMap = mutableMapOf<Any?,Any?>()
for ((key,value) in obj){
if (key == null){
if (value == null)
newMap[key] = value
else
newMap[key] = getValueFromCopiedCollection(value,copiedObjects)
} else {
if (value === null)
newMap[getValueFromCopiedCollection(key,copiedObjects)] = value
else
newMap[getValueFromCopiedCollection(key,copiedObjects)] = getValueFromCopiedCollection(value,copiedObjects)
}
}
copiedObjects[obj] = newMap
return newMap as T
}
is Set<*> -> {
val newSet = mutableSetOf<Any?>()
for (elem in obj){
if (elem == null)
newSet.add(elem)
else
newSet.add(getValueFromCopiedCollection(elem, copiedObjects))
}
copiedObjects[obj] = newSet
return newSet as T
}
is Date -> {
return Date(obj.time) as T
}
else -> {
println("deepCopy, class name: ${objClass.simpleName}")
val properties = objClass.memberProperties
val newCopy = objClassJava.newInstance()
properties.forEach {prop ->
val field = prop.javaField
if (field != null){
field.isAccessible = true
val value = field.get(obj)
val type = field.type
if (value == null)
field.set(newCopy, value)
else
field.set(newCopy, getValueFromCopiedCollection(value,copiedObjects))
}
}
copiedObjects[obj] = newCopy
return newCopy
}
}
//傻逼kotlin,前面都return完了先口,還要強(qiáng)行你這樣寫型奥,雖然可以return when,但是代碼不直觀
return obj
}
private fun<T: Any> getValueFromCopiedCollection(value: T,
copiedObjects: MutableMap<Any,Any>): T{
if (copiedObjects.containsKey(value)){
return copiedObjects[value] as T
}
var tempValue: Any? = null
if (!value::class.java.isPrimitive
&& value::class.javaPrimitiveType == null
&& !value::class.java.isArray
&& (value !is Collection<*>)){
tempValue = value::class.createInstance()
}
if (copiedObjects.isNotEmpty()){
tempValue = deepCopy(value,copiedObjects)
}
if (tempValue == null)
tempValue = value
else
copiedObjects[value] = tempValue
return tempValue as T
}
單元測試(用法)
class DeepCloneTest {
@Test
fun testThisClone() {
val thisCopy = deepCopy()
assertFalse(thisCopy === this)
}
@Test
fun testStringClone() {
val string = "水天滑稽天照八野滑稽石"
val stringClone = string.deepCopy()
assertNotNull(stringClone)
assertEquals(string, stringClone)
assertFalse(string === stringClone)
}
@Test
fun testIntegerPrimitiveClone() {
val integer = 100500
val integerClone = integer.deepCopy()
assertNotNull(integerClone)
assertTrue(integer == integerClone)
}
@Test
fun testIntegerClone() {
val integer = Integer(100500)
val integerClone = integer.deepCopy()
println(integerClone.toString())
assertNotNull(integerClone)
assertTrue(integer == integerClone)
}
@Test
fun testListClone() {
val listOfStrings = listOf("a", "b", "c")
val listOfStringsClone = listOfStrings.deepCopy() as List<String>
assertNotNull(listOfStringsClone)
assertTrue(listOfStringsClone.isNotEmpty())
assertTrue(listOfStringsClone.size == 3)
}
@Test
fun testSimpleObjectClone() {
val simpleObject = SimpleObject()
val simpleObjectClone = simpleObject.deepCopy()
assertNotNull(simpleObjectClone)
assertTrue(simpleObject == simpleObjectClone)
assertFalse(simpleObject === simpleObjectClone)
}
@Test
fun testComplexObjectClone() {
val complexObject = ComplexObject()
val complexObjectClone = complexObject.deepCopy()
assertNotNull(complexObjectClone)
assertFalse(complexObject === complexObjectClone)
}
}
data class SimpleObject(
var foo: String = "foo",
var bar: String = "bar"
)
class ComplexObject {
val noField: String
get() {
return "123"
}
var a = 1
get() = field + 1
set(value) {
field = value + 5
}
val b = 2
var listExample = mutableListOf(1, 2, 3)
var mapExample = mutableMapOf(1 to 1, 2 to 2, 3 to 3)
var arrExample = arrayOf(arrayOf(1, 2, 3), 2, 3)
var hashMapExample = hashMapOf(1 to 2, 3 to 2, 2 to 3)
var setExample = setOf(1, 2, 3)
var nullableInt: Int? = null
var date = Date()
val simpleNestedObject = SimpleObject()
}
全部通過就沒事了,具體實(shí)現(xiàn)和用法簡單看下代碼也就明白啦~