OC对象中copy和mutableCopy方法详解

前言

前段时间,看到在知识小集的交流群里正在讨论 copymutableCopy 这两个方法的相关特性。而这两个方法的使用,对于 Collection 来说,确实在运行的时候会有些不一样。主要还是为了记录一下,避免以后忘记,所以写了这篇文章。

理论概述

本文章将会讨论 CoreFoundationFoundation 框架里面的 Collection 类,当然也会简单的讲述自己定义的类,怎么实现 copymutableCopy 方法。

Collection 类的结论概括

首先,先查看有关 Collection 类的总结。当然,以下表格总结的结论只验证过一下这些类 NSStringNSMutableStringNSArrayNSMutableArrayNSDictionaryNSMutableDictionaryNSSetNSMutableSet

类名 操作 新对象 新类名 新元素对象 调用旧元素对应的Copy方法 拷贝类型 元素拷贝
NS* copy NO NS* NO NO 浅拷贝 NO
mutableCopy YES NSMutable* NO NO 深拷贝 NO
NSMutable* copy YES NS* NO NO 深拷贝 NO
mutableCopy YES NSMutable* NO NO 深拷贝 NO

由以上表格可以得出以下结论:

  1. Collection 类(容器)所有的 Copy 操作都只是对容器操作,不会对容器里的元素进行 Copy 操作。

  2. 只有 NS 开头的不可变字符串/数组/字典等集合类型调用 copy 方法才是浅拷贝(指针拷贝),不会生成新容器对象;其余的情况,则是深拷贝(内容拷贝),会生成对应的新容器对象,但容器内的元素还是原来的元素。

  3. 调用 copy 方法输出的是 NS 开头的不可变字符串/数组/字典等集合类型,调用 mutableCopy 方法输出的是 NSMutable 开头的可变字符串/数组/字典等集合类型(这里说的是输出的类型,不一定产生新容器对象)。

自定义类的结论概括

自定义类,调用 copymutableCopy 方法的输出规则其实主要还是看自己实现的代码控制。

需要自定义类实现 copy 方法,就必须遵守 NSCopying 协议,并实现 - (id)copyWithZone:(NSZone *)zone 方法,详情请看以下代码:

@interface Person : NSObject <NSCopying>

@end

@implementation Person

- (id)copyWithZone:(NSZone *)zone {
    //这里需要Copy操作返回什么,就会输出什么
    return self;
}

@end

需要自定义类实现 mutableCopy 方法,就必须遵守 NSMutableCopying 协议,并实现 - (id)mutableCopyWithZone:(NSZone *)zone 方法,详情请看以下代码:

@interface Person : NSObject <NSMutableCopying>

@end

@implementation Person

- (id)mutableCopyWithZone:(NSZone *)zone {
    //这里需要mutableCopy操作返回什么,就会输出什么
    return [[[self class] alloc] init];
}

@end

验证结论概括

接下来的章节就是验证以上的结论的过程,不过这里需要注意的是验证过程中打印出来的类名都是 NS*NSMutable*Class Clusters(类簇)
Apple 文档中是这样描述:

an architecture that groups a number of private, concrete subclasses under a public, abstract superclass. (一个在共有的抽象超类下设置一组私有子类的架构)

Class cluster 是 Apple 对抽象工厂设计模式的称呼。使用抽象类初始化返回一个具体的子类的模式的好处就是让调用者只需要知道抽象类开放出来的API的作用,而不需要知道子类的背后复杂的逻辑。验证结论过程的类簇对应关系请看这篇 Class Clusters 文档

NSString

首先,验证字符串常量 NSString 调用 copymutableCopy 的情况。运行以下的测试代码:

NSString *str = @"abc"; // __NSCFConstantString
NSString *copyStr = [str copy]; // __NSCFConstantString
NSMutableString *mutableCopyStr = [str mutableCopy]; // __NSCFString

NSLog(@"str(%@<%p>: %p): %@", [str class], &str, str, str);
NSLog(@"copyStr(%@<%p>: %p): %@", [copyStr class], &copyStr, copyStr, copyStr);
NSLog(@"mutableCopyStr(%@<%p>: %p): %@", [mutableCopyStr class], &mutableCopyStr, mutableCopyStr, mutableCopyStr);
[mutableCopyStr appendString:@"add"];
NSLog(@"mutableCopyStr(%@<%p>: %p): %@", [mutableCopyStr class], &mutableCopyStr, mutableCopyStr, mutableCopyStr);
NSLog(@"end");

打印的结果如下:

2018-08-17 15:17:00.323254+0800 TestCocoOC[12366:898331] str(__NSCFConstantString<0x7ffee96d80c8>: 0x106529148): abc
2018-08-17 15:17:00.323383+0800 TestCocoOC[12366:898331] copyStr(__NSCFConstantString<0x7ffee96d80c0>: 0x106529148): abc
2018-08-17 15:17:00.323637+0800 TestCocoOC[12366:898331] mutableCopyStr(__NSCFString<0x7ffee96d80b8>: 0x60c000240870): abc
2018-08-17 15:17:00.323855+0800 TestCocoOC[12366:898331] mutableCopyStr(__NSCFString<0x7ffee96d80b8>: 0x60c000240870): abcadd
2018-08-17 15:17:00.323918+0800 TestCocoOC[12366:898331] end

Class Clusters 分析:

  1. __NSCFConstantString 是字符串常量类,可看作 NSString
  2. __NSCFString 是字符串类,通常可看作 NSMutableString

根据以上测试代码和打印的结果显示,可进行以下分析:

  1. 变量 strcopyStr 打印出来的地址是相同的,都是 0x106529148而且类名相同,都是 __NSCFConstantString,说明只是浅拷贝,而且是 NSString
  2. 变量 mutableCopyStr 打印出的类名 __NSCFString,和其他的结果不一样,而且能够添加字符串,所以是 NSMutableString

根据以上验证可总结以下结果:

类名 操作 新对象 新类名 新元素对象 调用旧元素对应的Copy方法 拷贝类型 元素拷贝
NSString copy NO NSString NO NO 浅拷贝 NO
mutableCopy YES NSMutableString NO NO 深拷贝 NO

NSMutableString

可变字符串copymutableCopy操作,测试代码如下:

NSMutableString *str = [NSMutableString stringWithString:@"abc"]; // __NSCFString
NSMutableString *copyStr = [str copy]; //NSTaggedPointerString
NSMutableString *mutableCopyStr = [str mutableCopy]; // __NSCFString

NSLog(@"str(%@<%p>: %p): %@", [str class], &str, str, str);
NSLog(@"copyStr(%@<%p>: %p): %@", [copyStr class], &copyStr, copyStr, copyStr);
NSLog(@"mutableCopyStr(%@<%p>: %p): %@", [mutableCopyStr class], &mutableCopyStr, mutableCopyStr, mutableCopyStr);
NSLog(@"end");

打印的结果如下:

2018-08-17 13:39:26.601180+0800 TestCocoOC[9649:625978] str(__NSCFString<0x7ffeef6130c8>: 0x6000000599b0): abc
2018-08-17 13:39:26.601411+0800 TestCocoOC[9649:625978] copyStr(NSTaggedPointerString<0x7ffeef6130c0>: 0xa000000006362613): abc
2018-08-17 13:39:26.601701+0800 TestCocoOC[9649:625978] mutableCopyStr(__NSCFString<0x7ffeef6130b8>: 0x60000005ad00): abc
2018-08-17 13:39:26.602004+0800 TestCocoOC[9649:625978] end

Class Clusters 分析:

  1. NSTaggedPointerString 是字符串常量类,可看作 NSString,这个类具备 Tagged Pointer 特性。
  2. __NSCFString 是字符串类,通常可看作 NSMutableString

根据打印的结果可得出以下分析:

  1. strcopyStrmutableCopyStr 指针指向的地址都是不一样的,说明都生成了新对象。
  2. copy 方法生成不可变字符串对象,mutableCopy 方法生成的是可变字符串对象。

根据以上验证可总结以下结果:

类名 操作 新对象 新类名 新元素对象 调用旧元素对应的Copy方法 拷贝类型 元素拷贝
NSMutableString copy YES NSString NO NO 深拷贝 NO
mutableCopy YES NSMutableString NO NO 深拷贝 NO

NSArray

数组的拷贝操作,都是针对数组容器对象处理,数组里面的元素对象都是不变的。测试代码如下:

Person *person1 = [[Person alloc] init];
Person *person2 = [[Person alloc] init];
Person *person3 = [[Person alloc] init];
NSArray *array = @[person1, person2, person3]; //__NSArrayI
NSArray *copyArray = [array copy]; //__NSArrayI
NSArray *mutableCopyArray = [array mutableCopy]; //__NSArrayM

NSLog(@"array(%@<%p>: %p): %@", [array class], &array, array, array);
NSLog(@"copyArray(%@<%p>: %p): %@", [copyArray class], &copyArray, copyArray, copyArray);
NSLog(@"mutableCopyArray(%@<%p>: %p): %@", [mutableCopyArray class], &mutableCopyArray, mutableCopyArray, mutableCopyArray);
NSLog(@"end");

打印的结果如下:

2018-08-17 13:39:43.724273+0800 TestCocoOC[9649:625978] array(__NSArrayI<0x7ffeef613090>: 0x60c00024c3f0): (
"<Person: 0x60c0004246c0>",
"<Person: 0x60c000421ae0>",
"<Person: 0x60c000422ae0>"
)
2018-08-17 13:39:43.724481+0800 TestCocoOC[9649:625978] copyArray(__NSArrayI<0x7ffeef613088>: 0x60c00024c3f0): (
"<Person: 0x60c0004246c0>",
"<Person: 0x60c000421ae0>",
"<Person: 0x60c000422ae0>"
)
2018-08-17 13:39:43.724713+0800 TestCocoOC[9649:625978] mutableCopyArray(__NSArrayM<0x7ffeef613080>: 0x60c00024c2a0): (
"<Person: 0x60c0004246c0>",
"<Person: 0x60c000421ae0>",
"<Person: 0x60c000422ae0>"
)
2018-08-17 13:39:43.724984+0800 TestCocoOC[9649:625978] end

Class Clusters 分析:

  1. __NSArrayI 是不可变数组子类,可看作 NSArray
  2. __NSArrayM 是可变数组子类,通常可看作 NSMutableArray

根据以上测试代码和打印的结果显示,可进行以下分析:

  1. 变量 arraycopyArray 打印出来的地址是相同的,都是 0x60c00024c3f0而且类名相同,都是 __NSArrayI,说明只是浅拷贝,而且是 NSArray
  2. 变量 mutableCopyStr 打印出的类名 __NSArrayM,所以是 NSMutableArray
  3. 数组里的元素打印的对象地址都是一样的。

根据以上验证可总结以下结果:

类名 操作 新对象 新类名 新元素对象 调用旧元素对应的Copy方法 拷贝类型 元素拷贝
NSArray copy NO NSArray NO NO 浅拷贝 NO
mutableCopy YES NSMutableArray NO NO 深拷贝 NO

NSMutableArray

不可变数组和可变数组的关系其实是子类和父类的关系。以下就是验证可变数组拷贝操作的测试代码:

Person *person1 = [[Person alloc] init];
Person *person2 = [[Person alloc] init];
Person *person3 = [[Person alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] initWithArray:@[person1, person2, person3]]; // __NSArrayM
//NSMutableArray *array = [[NSMutableArray alloc] initWithArray:@[person1, person2, person3] copyItems:YES]; //初始化只做一次拷贝,会触发 Person 的 copy 方法
NSMutableArray *copyArray = [array copy]; //__NSArrayI
NSMutableArray *mutableCopyArray = [array mutableCopy]; //__NSArrayM
NSLog(@"array(%@<%p>: %p): %@", [array class], &array, array, array);
NSLog(@"copyArray(%@<%p>: %p): %@", [copyArray class], &copyArray, copyArray, copyArray);
NSLog(@"mutableCopyArray(%@<%p>: %p): %@", [mutableCopyArray class], &mutableCopyArray, mutableCopyArray, mutableCopyArray);
NSLog(@"end");

打印的结果如下:

2018-08-17 13:41:31.266514+0800 TestCocoOC[9649:625978] array(__NSArrayM<0x7ffeef613090>: 0x6040002440b0): (
"<Person: 0x604000039460>",
"<Person: 0x6040000392c0>",
"<Person: 0x6040000391c0>"
)
2018-08-17 13:41:31.266738+0800 TestCocoOC[9649:625978] copyArray(__NSArrayI<0x7ffeef613088>: 0x604000243d20): (
"<Person: 0x604000039460>",
"<Person: 0x6040000392c0>",
"<Person: 0x6040000391c0>"
)
2018-08-17 13:41:31.267018+0800 TestCocoOC[9649:625978] mutableCopyArray(__NSArrayM<0x7ffeef613080>: 0x604000242820): (
"<Person: 0x604000039460>",
"<Person: 0x6040000392c0>",
"<Person: 0x6040000391c0>"
)
2018-08-17 13:41:31.267208+0800 TestCocoOC[9649:625978] end

Class Clusters 分析:

  1. __NSArrayI 是不可变数组子类,可看作 NSArray
  2. __NSArrayM 是可变数组子类,通常可看作 NSMutableArray

根据以上测试代码和打印的结果显示,可进行以下分析:

  1. 变量 arraycopyArraymutableCopyArray 打印出来的地址是不相同的,说明都是容器的深拷贝。
  2. 数组里的元素打印的对象地址都是一样的。

根据以上验证可总结以下结果:

类名 操作 新对象 新类名 新元素对象 调用旧元素对应的Copy方法 拷贝类型 元素拷贝
NSMutableArray copy YES NSArray NO NO 深拷贝 NO
mutableCopy YES NSMutableArray NO NO 深拷贝 NO

NSDictionary

key-value 其实就是 Hash 表,里面的 key 都是字符串常量。当然,拷贝操作也不会对元素做处理。验证拷贝特性的测试代码如下:

Person *person = [[Person alloc] init];
NSDictionary *dict = @{@"key":@"qwe",
                       @"num":@1,
                       @"person": person}; //__NSDictionaryI
NSDictionary *copyDict = [dict copy]; //__NSDictionaryI
NSDictionary *mutableCopyDict = [dict mutableCopy]; //__NSDictionaryM
NSLog(@"dict(%@<%p>: %p): %@", [dict class], &dict, dict, dict);
NSLog(@"copyDict(%@<%p>: %p): %@", [copyDict class], &copyDict, copyDict, copyDict);
NSLog(@"mutableCopyDict(%@<%p>: %p): %@", [mutableCopyDict class], &mutableCopyDict, mutableCopyDict, mutableCopyDict);
NSLog(@"end");

打印的结果如下:

2018-08-17 13:41:48.389669+0800 TestCocoOC[9649:625978] dict(__NSDictionaryI<0x7ffeef613088>: 0x6000000730c0): {
key = qwe;
num = 1;
person = "<Person: 0x600000037da0>";
}
2018-08-17 13:41:48.389843+0800 TestCocoOC[9649:625978] copyDict(__NSDictionaryI<0x7ffeef613080>: 0x6000000730c0): {
key = qwe;
num = 1;
person = "<Person: 0x600000037da0>";
}
2018-08-17 13:41:48.390006+0800 TestCocoOC[9649:625978] mutableCopyDict(__NSDictionaryM<0x7ffeef613078>: 0x600000036900): {
key = qwe;
num = 1;
person = "<Person: 0x600000037da0>";
}
2018-08-17 13:41:48.390375+0800 TestCocoOC[9649:625978] end

Class Clusters 分析:

  1. __NSDictionaryI 是不可变字典子类,可看作 NSDictionary
  2. __NSDictionaryM 是可变字典子类,通常可看作 NSMutableDictionary

根据以上测试代码和打印的结果显示,可进行以下分析:

  1. 变量 dictcopyDict 打印出来的地址是相同的,都是 0x6000000730c0而且类名相同,都是 __NSDictionaryI,说明只是浅拷贝,而且是 NSDictionary
  2. 变量 mutableCopyDict 打印出的类名 __NSDictionaryM,所以是 NSMutableDictionary
  3. 打印出来的元素对象(Person)地址都是一样的。

根据以上验证可总结以下结果:

类名 操作 新对象 新类名 新元素对象 调用旧元素对应的Copy方法 拷贝类型 元素拷贝
NSDictionary copy NO NSDictionary NO NO 浅拷贝 NO
mutableCopy YES NSMutableDictionary NO NO 深拷贝 NO

NSMutableDictionary

可变字典类的验证拷贝操作的测试代码如下:

Person *person = [[Person alloc] init];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{@"key":@"qwe",
                                                                            @"num":@1,
                                                                            @"person": person}]; // __NSDictionaryM
NSMutableDictionary *copyDict = [dict copy]; //__NSFrozenDictionaryM
NSMutableDictionary *mutableCopyDict = [dict mutableCopy]; //__NSDictionaryM
NSLog(@"dict(%@<%p>: %p): %@", [dict class], &dict, dict, dict);
NSLog(@"copyDict(%@<%p>: %p): %@", [copyDict class], &copyDict, copyDict, copyDict);
NSLog(@"mutableCopyDict(%@<%p>: %p): %@", [mutableCopyDict class], &mutableCopyDict, mutableCopyDict, mutableCopyDict);
NSLog(@"end");

打印的结果如下:

2018-08-17 13:42:18.754223+0800 TestCocoOC[9649:625978] dict(__NSDictionaryM<0x7ffeef613088>: 0x604000039040): {
key = qwe;
num = 1;
person = "<Person: 0x6040000391e0>";
}
2018-08-17 13:42:18.754484+0800 TestCocoOC[9649:625978] copyDict(__NSFrozenDictionaryM<0x7ffeef613080>: 0x6040000392c0): {
key = qwe;
num = 1;
person = "<Person: 0x6040000391e0>";
}
2018-08-17 13:42:18.754631+0800 TestCocoOC[9649:625978] mutableCopyDict(__NSDictionaryM<0x7ffeef613078>: 0x604000039400): {
key = qwe;
num = 1;
person = "<Person: 0x6040000391e0>";
}
2018-08-17 13:42:18.754877+0800 TestCocoOC[9649:625978] end

Class Clusters 分析:

  1. __NSDictionaryI 是不可变字典子类,可看作 NSDictionary
  2. __NSFrozenDictionaryM可变字典类的副本类,可看作 NSDictionary
  3. __NSDictionaryM 是可变字典子类,通常可看作 NSMutableDictionary

根据以上测试代码和打印的结果显示,可进行以下分析:

  1. 变量 dictcopyDictmutableCopyDict 打印出来的地址是不相同的,说明都是容器的深拷贝。
  2. 打印出来的元素对象(Person)地址都是一样的。

根据以上验证可总结以下结果:

类名 操作 新对象 新类名 新元素对象 调用旧元素对应的Copy方法 拷贝类型 元素拷贝
NSMutableDictionary copy YES NSDictionary NO NO 深拷贝 NO
mutableCopy YES NSMutableDictionary NO NO 深拷贝 NO

NSSet

不可变去重无序集合,里面的元素都是唯一的。验证拷贝操作的测试代码如下:

Person *person1 = [[Person alloc] init];
Person *person2 = [[Person alloc] init];
Person *person3 = [[Person alloc] init];
NSSet *set = [[NSSet alloc] initWithArray:@[person1, person2, person3]]; // __NSSetI
NSSet *copySet = [set copy]; //__NSSetI
NSSet *mutableCopySet = [set mutableCopy]; //__NSSetM
NSLog(@"set(%@<%p>: %p): %@", [set class], &set, set, set);
NSLog(@"copySet(%@<%p>: %p): %@", [copySet class], &copySet, copySet, copySet);
NSLog(@"mutableCopySet(%@<%p>: %p): %@", [mutableCopySet class], &mutableCopySet, mutableCopySet, mutableCopySet);
NSLog(@"end");

打印的结果如下:

2018-08-17 13:43:29.316827+0800 TestCocoOC[9813:648649] set(__NSSetI<0x7ffee4e07090>: 0x60400024d5c0): {(
<Person: 0x60400003b360>,
<Person: 0x60400003b280>,
<Person: 0x60400003b1e0>
)}
2018-08-17 13:43:29.316999+0800 TestCocoOC[9813:648649] copySet(__NSSetI<0x7ffee4e07088>: 0x60400024d5c0): {(
<Person: 0x60400003b360>,
<Person: 0x60400003b280>,
<Person: 0x60400003b1e0>
)}
2018-08-17 13:43:29.317350+0800 TestCocoOC[9813:648649] mutableCopySet(__NSSetM<0x7ffee4e07080>: 0x60400003b0e0): {(
<Person: 0x60400003b360>,
<Person: 0x60400003b280>,
<Person: 0x60400003b1e0>
)}
2018-08-17 13:43:29.317455+0800 TestCocoOC[9813:648649] end

Class Clusters 分析:

  1. __NSSetI 是不可变去重无序集合子类,可看作 NSSet
  2. __NSSetM 是可变去重无序集合子类,通常可看作 NSMutableSet

根据以上测试代码和打印的结果显示,可进行以下分析:

  1. 变量 setcopySet 打印出来的地址是相同的,都是 0x60400024d5c0而且类名相同,都是 __NSSetI,说明只是浅拷贝,而且是 NSSet
  2. 变量 mutableCopySet 打印出的类名 __NSSetM,所以是 NSMutableSet
  3. 打印出来的元素对象(Person)地址都是一样的。

根据以上验证可总结以下结果:

类名 操作 新对象 新类名 新元素对象 调用旧元素对应的Copy方法 拷贝类型 元素拷贝
NSSet copy NO NSSet NO NO 浅拷贝 NO
mutableCopy YES NSMutableSet NO NO 深拷贝 NO

NSMutableSet

可变去重无序集合,里面的元素都是唯一的。验证拷贝操作的测试代码如下:

Person *person1 = [[Person alloc] init];
Person *person2 = [[Person alloc] init];
Person *person3 = [[Person alloc] init];
NSMutableSet *set = [[NSMutableSet alloc] initWithArray:@[person1, person2, person3]]; // __NSSetM
NSMutableSet *copySet = [set copy]; //__NSSetI
NSMutableSet *mutableCopySet = [set mutableCopy]; //__NSSetM
NSLog(@"set(%@<%p>: %p): %@", [set class], &set, set, set);
NSLog(@"copySet(%@<%p>: %p): %@", [copySet class], &copySet, copySet, copySet);
NSLog(@"mutableCopySet(%@<%p>: %p): %@", [mutableCopySet class], &mutableCopySet, mutableCopySet, mutableCopySet);
NSLog(@"end");

打印的结果如下:

2018-08-17 13:43:52.278444+0800 TestCocoOC[9813:648649] set(__NSSetM<0x7ffee4e07090>: 0x60400003b360): {(
<Person: 0x60400003b2a0>,
<Person: 0x60400003b040>,
<Person: 0x60400003b160>
)}
2018-08-17 13:43:52.278611+0800 TestCocoOC[9813:648649] copySet(__NSSetI<0x7ffee4e07088>: 0x60400024dd10): {(
<Person: 0x60400003b2a0>,
<Person: 0x60400003b040>,
<Person: 0x60400003b160>
)}
2018-08-17 13:43:52.278686+0800 TestCocoOC[9813:648649] mutableCopySet(__NSSetM<0x7ffee4e07080>: 0x60400003b140): {(
<Person: 0x60400003b2a0>,
<Person: 0x60400003b040>,
<Person: 0x60400003b160>
)}
2018-08-17 13:43:52.279086+0800 TestCocoOC[9813:648649] end

Class Clusters 分析:

  1. __NSSetI 是不可变去重无序集合子类,可看作 NSSet
  2. __NSSetM 是可变去重无序集合子类,通常可看作 NSMutableSet

根据以上测试代码和打印的结果显示,可进行以下分析:

  1. 变量 setcopySetmutableCopySet 打印出来的地址是不相同的,说明都是容器的深拷贝。
  2. 数组里的元素打印的对象地址都是一样的。

根据以上验证可总结以下结果:

类名 操作 新对象 新类名 新元素对象 调用旧元素对应的Copy方法 拷贝类型 元素拷贝
NSMutableSet copy YES NSSet NO NO 深拷贝 NO
mutableCopy YES NSMutableSet NO NO 深拷贝 NO

结论分析

上一节的验证结果符合结论概括所描述的。虽然验证过程输出的类比较复杂,Apple 引进了 Class ClustersTagged Pointer 的设计思想,但是还是这不妨碍拷贝操作的总结。不过有时间的话还是研究一下这两个设计思想,对以后设计架构会大有进步。
根据这篇文章的结论概括,在日常开发中可注意以下几点:

  1. Objective-C 类中的属性,NSMutable 开头的可变集合类属性不要用 copy 关键字去修饰,以为每次赋值操作拷贝出来的都是不可变集合类了。
  2. CollectioncopymutableCopy 方法,集合里面的元素对象都不会发生拷贝操作。简单的来说,只是对容器操作。
  3. 自定义类的拷贝操作是自己控制的。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容