对象的可变性以及深浅拷贝

一、对象的可变性

OC的类有可变的类和不可变的类,这与变量和常量是不同的。可变类生成的对象是可变对象,不可变类生成的对象是不可变对象。

可变对象,不可变对象,变量,常量

可变对象:内容可以改变的对象。
不可变对象:内容不可以更改的对象。
变量:值可以更改。
常量:值不可以更改。
可变对象可以是常量也可以是变量。
不可变对象可以是常量,也可以是变量。

对象为什么要区分可变和不可变呢?

这是为了从实现的复杂度方面考虑的。例如,要允许删除或者增加字符串的某个字母,或者给数组追加成百上千的元素,这就要在一开始设计的时候做好对象的数据结构和方法。如果一开始就确定这个对象是不可变的,那么就不需要为他设计那么复杂的数据结构了,实现起来也简单的多。

例如:给路径"/Users/wenhuanhuan/Desktop/a.txt"更改文件后缀名为”a.bak”

实现方法当然是各种各样,各有千秋,这里就举出三种实现方法,其中有用到可变与不可变的对象哟。

//方法一
        NSString * oldFile2 = @"/Users/wenhuanhuan/Desktop/a.txt”;
        NSString * newP = [oldFile2 stringByReplacingOccurrencesOfString:@"a.txt" withString:@"a.bak”];
        NSLog(@"方法一:新的路径: %@", newP);

//方法二
        
        NSString * path = @"/Users/wenhuanhuan/Desktop/a.txt”;
        //获取文件名
        NSString * fileName = [path lastPathComponent];
        //删除文件的扩展名
        fileName = [fileName stringByDeletingPathExtension];
        //给文件加上新的扩展名.bak
        fileName = [fileName stringByAppendingPathExtension:@"bak”];
        //重新生成新的路径
        NSString * tempPath = [path stringByDeletingLastPathComponent];
        tempPath = [tempPath stringByAppendingPathComponent:fileName];
        NSLog(@"方法二:新的路径是: %@", tempPath);
//方法三
        NSString * oldFile = @"/Users/wenhuanhuan/Desktop/a.txt”;
        //分解路径为数组
        NSMutableArray *olds = [NSMutableArray arrayWithArray:[oldFile componentsSeparatedByString:@"/“]];
        //取最后一个元素也就是a.txt
        NSString *lastStr = [olds lastObject];
        //再次分解a.txt为数组,取后缀
        NSMutableArray *oldFileName = [NSMutableArray arrayWithArray:[lastStr componentsSeparatedByString:@".”]];
        //更改后缀
        [oldFileName replaceObjectAtIndex:oldFileName.count - 1 withObject:@"bak”];
        //重新拼接
        [oldFileName insertObject:@"." atIndex:1];
        NSMutableString * tempFileName = [oldFileName componentsJoinedByString:@","].mutableCopy;
        tempFileName = [tempFileName stringByReplacingOccurrencesOfString:@"," withString:@""].mutableCopy;
        [olds removeLastObject];
        [olds addObject:tempFileName];
        
        NSString * newPath = [olds componentsJoinedByString:@"/“];
        NSLog(@"方法三:新路径: %@", newPath);

运行结果:


image.png

说起OC对象的可变和不可变,就不得不提到一个方法,就是:
-(id)mutableCopy;
这是声明在NSObject中的方法。


image.png

此方法能够将不可变对象变成可变对象,例如,上面例子中的:
NSMutableString * tempFileName = [oldFileName componentsJoinedByString:@","].mutableCopy;

[oldFileName componentsJoinedByString:@",”] 这个方法返回的是一个NSString对象,是一个不可变对象,但是我们需要一个可变的字符串,这个时候就可使用mutableCopy方法,让他变成一个可变的字符串,最后我们就可以更改这个可变的字符串了。

那么我们再来深入想一想,我们使用这个方法生成的对象和原来的对象是不是一个地址呢?有何关系呢?

    NSString * str1 = @“hello”;
    NSMutableString * str2 = str1.mutableCopy;
    NSLog(@"str1: %p, str2: %p", str1, str2);

看看结果:


image.png

地址是不一样的,也就是这是两个对象。

在NSObject中还有一个方法,叫做copy,在我们的截图中也可以看到,就在mutableCopy的上一行,我们也来试一试。
看看结果:


image.png

str1和str3的地址是一样的,也就是使用的同一块地址空间,只是引用计数增加了,这个叫做『浅拷贝』。
这里,我们再来看看几个概念,『单层深拷贝』,『浅拷贝』,『完全拷贝』。

二、深浅拷贝以及完全深拷贝

浅拷贝:就是像上面的例子一样,只是复制了指针,对象的地址并不改变,只是给对象增加了一个引用计数。

单层深拷贝:这里的单层深复制是针对集合类来说的,指的是只复制外层的集合类对象,里面的元素并没有复制。

完全拷贝:也是针对集合类来说的,完全拷贝不仅复制了对象自身,生成了新的对象,集合中的元素对象也被复制了一份新的。

我们用代码来具体的看一看到底什么是深浅拷贝呢。

  • 浅拷贝

1.对不可变对象发送copy,无论对象的接收者是可变的还是不可变的,他们的地址不变,是浅拷贝。
注意:无论对象接收者的类型是可变的还是不可变的,使用copy复制出来的对象都是不可变的。因为copy方法返回类型是id,使用可变指针接收也不会报错,但是,一旦使用可变对象的方法去改变它的时候,就会造成崩溃。

    NSString * str1 = @“hello”;
    NSString * str2 = str1.copy;
    //这是一种不安全的写法,因为mstr2实质上是不可变的,
   //使用mstr2更改其中的元素的时候,会崩溃。
    NSMutableString * mstr2 = str1.copy;
    NSLog(@"str1: %p, str2: %p, mstr2: %p", str1, str2, mstr2);
    
    //使用copy出来的对象都是不可变对象,即使使用可变指针来接收,对象本身依然是不可变的。
//    [mstr2 appendString:@"小苗儿"];//崩溃
//    NSLog(@"%@", mstr2);

打印结果:


image.png

从结果可以看出来,str1,str2,mstr的地址都是一样的,是浅拷贝。

我们更改一下str1的值看一看,结果会如何呢?str2,str3,mstr2,mstr3的值又会不会变化呢?

    NSLog(@"更改str的值”);
    str1 = @"你好!”;
    NSLog(@"str1: %p, str2: %p, mstr2: %p", str1, str2, mstr2);
    NSLog(@"str1: %@", str1);
    NSLog(@"str2: %@", str2);
    NSLog(@"mstr2: %@", mstr2);
    NSLog(@"str3: %@", str3);
    NSLog(@"mstr3: %@", mstr3);

打印结果


image.png

从打印结果可以看出,str1的值更改之后,它的地址改变了,而str2等的地址没有改变,只有str1的值变成了”你好!”,其他值没有更改。

我们用示意图来理解,一目了然。

image.png

我们再来看看直接赋值,一个值更改了,另一个会不会改变。

   NSString * s1 = @"明天是个好天气”;
   NSString * s2 = s1;
   NSLog(@"更改前, s1: %p, s2: %p", s1, s2);
   s2 = @"下雨啦”;
   NSLog(@"更改后,s1: %p, s2: %p", s1, s2);
   NSLog(@"s1: %@, s2: %@", s1, s2);

打印结果:


image.png

跟浅拷贝一样,值更改后,地址就改变了,对s1没有影响。

我们再试试别的类型,例如NSNumber。

//再来看看NSNumber类型,不能使用mutableCopy哟
    NSNumber * num1 = [NSNumber numberWithInt:20];
    NSNumber * num2 = num1.copy;
    NSNumber * num3 = num1.copy;
    NSLog(@"num1: %p", num1);
    NSLog(@"num2: %p", num2);
    NSLog(@"num3: %p", num3);
    
    num1 = @200;
    NSLog(@"num1: %@, num2: %@, num3: %@", num1, num2, num3);

打印结果:

image.png

跟NSString一样,更改前,地址是一样的,是浅拷贝,更改后,被更改的对象的地址改变了,其他的地址不变,值也没有影响。

再试试NSArray。

   NSArray * array = @[@"1", @"2", @"3”];
   NSArray * array2 = array.copy;//浅拷贝
   NSMutableArray * array3 = array.mutableCopy; //深拷贝
   NSArray * array4 = array;//直接赋值
   NSLog(@"array: %p, array2: %p, array3: %p, array4: %p", array, array2, array3, array4);

   printArray(array);
   printArray(array2);
   printArray(array3);
   printArray(array4);

   NSLog(@"更改array的值”);
   array = @[@"5", @"6", @"7", @"8”];
   NSLog(@"array: %p, array2: %p, array3: %p, array4: %p", array, array2, array3, array4);
   printArray(array);
   printArray(array2);
   printArray(array3);
   printArray(array4);

printArray方法

void printArray(NSArray * array) {
    printf("\n\n”);
    for (NSString * obj in array) {
        NSLog(@"%p, %@", obj, obj);
    }
}

备注:我新建的是控制台程序,方法声明在main函数中,所以方法的声明跟C语言一样。
在main函数的最上面,加上方法声明。

image.png

继续上面那个测试,看看数组的值更改前后,地址是否变化呢。
打印结果


image.png

值更改前,除了深拷贝的array3的地址不一样之外,其他地址都是一样的。再看看值更改之后。

image.png

被更改的array的地址发生了变化,与上面的NSString,NSNumber的情况都一样。

总结:
对不可变对象发送copy消息,是浅拷贝,地址不变;
更改浅拷贝出来的对象的值,被更改的对象地址发生改变,其他浅拷贝出来的对象值不受影响,原对象也不受影响。
copy出来的对象都是不可变对象。

2.对不可变对象发送mutableCopy,地址改变,是深拷贝

  NSString * str3 = str1.mutableCopy;
  NSMutableString * mstr3 = str1.mutableCopy;
  NSLog(@"str1: %p, str3: %p, mstr3: %p", str1, str3, mstr3);

打印结果

image.png

结果发现,三个地址都是不一样的,是不同的对象,也就是深拷贝了。

3.对可变对象发送copy消息,地址改变,是深拷贝

    NSMutableString * ms1 = [NSMutableString stringWithString:@"world”];
    NSString * ims1 = ms1.copy;
    NSMutableString * ms1_1 = ms1.mutableCopy;

4.对可变对象发送mutableCopy,地址改变,是深拷贝

    NSMutableString * ms2 = ms1.mutableCopy;
    NSLog(@"ms1: %p, ims1: %p, ms1_1: %p, ms2:%p",ms1,ims1,ms1_1,ms2);
    
    ms1 = [NSMutableString stringWithString:@"世界那么大”];
    NSLog(@"ms1: %@", ms1);
    NSLog(@"ims1: %@", ims1);
    NSLog(@"ms1_1: %@", ms1_1);
    NSLog(@"ms2: %@", ms2);

打印结果


image.png

不同地址的对象之间,值得更改肯定是互不影响的。

深拷贝示意图


image.png

总结:
1.对不可变对象发送copy消息,地址不变,是浅拷贝;
2.对不可变对象发送mutableCopy,地址改变,是深拷贝;
3.对可变对象发送copy消息,地址改变,是深拷贝;
4.对可变对象发送mutableCopy,地址改变,是深拷贝。

快速记忆:
只有不可变对象的copy是浅拷贝,其他都是深拷贝。
简化记忆:
不可变+copy,浅拷贝;其他深拷贝。

说到这里,似乎已经说完了深浅拷贝了,不就这四种情况吗?还有别的吗?有,深拷贝还能分出个单层深拷贝和完全深拷贝呢。

单层深拷贝和完全深拷贝

单层深拷贝和完全拷贝是针对集合类型说的,因为集合类型才会分层,才有嵌套。

  • 单层深拷贝
    只拷贝对象的一层或几层,不能把所有的元素都拷贝一份。

  • 完全深拷贝
    无论集合有几层,所有的元素都是新的地址,新的对象。

我们就以数组为例,来看看吧。

    NSMutableString * obj = [NSMutableString stringWithString:@"one”];
    NSMutableArray * marray = [NSMutableArray arrayWithObjects:obj, @"two", @"three", nil];
    NSMutableArray * marray1 = [marray mutableCopy];
    NSArray * imarray = [marray copy];
    printf("\n\n”);
    NSLog(@"数组地址打印:”);
    NSLog(@"marray: %p", marray);
    NSLog(@"marray1: %p", marray1);
    NSLog(@"imarray: %p", imarray);
    
    NSLog(@"数组元素的地址打印:”);
    printArray(marray);
    printArray(marray1);
    printArray(imarray);
    
    NSLog(@"更改数组第一个元素的值”);
    [obj appendString:@" add some datas”];
    NSLog(@"更改后数组元素的地址打印:”);
    printArray(marray);
    printArray(marray1);
    printArray(imarray);
    NSLog(@"marray : %@", marray);
    NSLog(@"marray1 : %@", marray1);
    NSLog(@"imarray : %@", imarray);

打印结果

数组地址:


image.png

结果看出,对可变数组发送copy或者mutableCopy,都是深拷贝,新的对象地址与原数组是不一样的。

再看看数组的元素的地址:


image.png

我们发现,数组的元素的地址并没有改变,跟原来数组中的元素地址还是一样的,这就是单层深拷贝了。

再看看更改了元素之后呢。


image.png
image.png

发现,第一个元素的地址没有改变,跟之前一样,其他数组的第一个元素的值也改变了。

我们用示意图来表示单层深拷贝,如下图:


image.png

image.png

汇总一个图

image.png

那么,如何让数组的元素也进行拷贝呢?我们先试试第一种方法。

方法一, 使用 - (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;

    NSMutableArray * newArray = [[NSMutableArray alloc] initWithArray:marray copyItems:YES];
    [obj appendString:@" new item”];
    printArray(marray);
    printArray(newArray);

看看打印结果


image.png

第一个元素的地址改变了,并且,更改了第一个元素的值之后,newArray的值没有改变,似乎解决了问题,这是完全拷贝吗?其实,不然。

注意:
此方法使元素中均执行[xxx copy]方法。这也是在marray中放入NSMutableString的原因。如果放入的是NSArray或者NSString,执行copy后,只会发生指针复制, 像@“two”,@“three”,看看打印地址,跟marray中的地址还是一样的;如果放入的是未实现NSCopying协议的对象,如自定义对象,调用这个方法甚至会crash,因为自定义对象没有copy方法。

如果把marray放在一个可变的数组中,作为数组的一个元素,上面的方法再次失效,我们一起看看。

    NSMutableString * red = [NSMutableString stringWithString:@"red”];
    NSMutableString * yellow = [NSMutableString stringWithString:@"yellow”];
    NSMutableArray * bigArray = [NSMutableArray arrayWithObjects:marray, red, yellow, nil];
    NSMutableArray * bigArrayCopy = [[NSMutableArray alloc] initWithArray:bigArray copyItems:YES];
    NSMutableString * tempStr = bigArray[0][0];
    [tempStr insertString:@"11111" atIndex:0];
    NSLog(@"bigArray: %@", bigArray);
    NSLog(@"bigArrayCopy: %@", bigArrayCopy);

打印结果:


image.png

说明它们的元素共用了一块地址,一个值更改了,另一个也更改了。所以,使用上面的方法,并没有完全拷贝,
[[NSMutableArray alloc] initWithArray:bigArray copyItems:YES]
这个方法只能深复制一层,再多套一层就不行了。
那么到底怎样才能完全拷贝呢?我们可以使用归档和解档。

方法二, 使用归档和解档

//方法二,使用归档和解档
   NSMutableArray * myArrayCopy = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:bigArray]];
   NSMutableString * tempStr2 = bigArray[0][0];
   [tempStr2 insertString:@"0000" atIndex:0];
   NSLog(@"bigArray: %@", bigArray);
   NSLog(@"myArrayCopy: %@", myArrayCopy);

看看结果:


image.png

看起来是好用的哟。

多嵌套几层试试,看看还是好用的吗?

    NSMutableString * xiaoming = [NSMutableString stringWithString:@"xiaoming”];
    NSMutableArray * names = [NSMutableArray arrayWithObjects:xiaoming, @"xiaohua", @"xiaoli", nil];
    NSMutableArray * students = [NSMutableArray arrayWithObjects:names, @"OC", @"Java", nil];
    NSMutableArray * people = [NSMutableArray arrayWithObjects:students,@"beijing", nil];
    NSMutableArray * peopleCopy = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:people]];
    NSMutableString * temp = people[0][0][0];
    [temp appendString:@" 100 “];
    NSLog(@"people: %@", people);
    NSLog(@"peopleCopy: %@", peopleCopy);

打印结果:


image.png

依然是好用的,说明使用归档和解档实现了完全拷贝。

如果是我们自定义的类,可不可以copy呢?

自定义类的copy

我们新建一个类,起名儿叫做ClassA,如下图:


image.png

classA.h:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface ClassA : NSObject

@property(nonatomic, copy)NSString * name;
@property(nonatomic, assign)int num;
@property(nonatomic, strong)NSArray * array;

-(instancetype)initWithName:(NSString *)name num:(int)num;

@end

NS_ASSUME_NONNULL_END

classA.m

#import “ClassA.h”

@implementation ClassA

-(instancetype)initWithName:(NSString *)name num:(int)num {
    if (self = [super init]) {
        self.name = name;
        self.num = num;
        self.array = @[];
    }
    return self;
}

@end

在main函数中试试

#import <Foundation/Foundation.h>
#import “ClassA.h”

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here…
        NSLog(@"Hello, World!”);
        
        ClassA * a = [[ClassA alloc] initWithName:@"小明" num:1];
        ClassA * a2 = a.copy;
        NSLog(@"a: %@", a);
        NSLog(@"a: %@", a2);
        
    }
    return 0;
}

运行,崩溃,崩溃信息如下:


image.png
image.png

说ClassA没有实现copyWithZone方法。
原来,自定义类要想使用copy方法,就需要遵守NSCopying协议,实现copyWithZone方法,我们来试一试。
把classA修改如下:


image.png
image.png

再次运行程序,没有崩溃,看看结果


image.png

由于我们的copyWithZone中写的是浅复制,直接返回的是自身,所以,我们的两个对象是一样的,地址也是一样的。我们重写一下description方法,看看他们的属性是否一样。


image.png

在运行看看


image.png

属性也是相同的,属性的地址也是一样的,如下图:


image.png

如果我想在自定义类实现copy深复制,该如何实现呢?

单层深复制

//单层深复制
-(id)copyWithZone:(NSZone *)zone {
    ClassA * a = [[ClassA allocWithZone:zone] init];
    a.name = self.name;
    a.num = self.num;
    a.array = self.array;
    return a;
}

测试:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here…
        NSLog(@"Hello, World!”);
        
        ClassA * a = [[ClassA alloc] initWithName:@"小明" num:1];
        ClassA * a2 = a.copy;
        NSLog(@"a: %p, %@", a, a);
        NSLog(@"a2: %p, %@", a2, a2);
        
    }
    return 0;
}

结果:


image.png

地址不同哟,是两个对象。为什么说是单层深复制呢?我们来看看他们的属性地址是否一样呢?
我们修改一下description方法,让他打印出属性的地址来。

- (NSString *)description
{
    return [NSString stringWithFormat:@"对象地址%p: name: %p, %@, num: %d, array: %p, %@",self, self.name, self.name, self.num, self.array, self.array];
}

测试:

       ClassA * a = [[ClassA alloc] initWithName:@"小明" num:1];
        NSMutableString * str = [NSMutableString stringWithString:@"1”];
        a.array = @[str, @"2", @"3”];
        ClassA * a2 = a.copy;
        NSLog(@"a: %@", a);
        NSLog(@"a2: %@", a2);

看看结果:


image.png

属性的地址是一样的。我们更改array的元素的值再看看。

       ClassA * a = [[ClassA alloc] initWithName:@"小明" num:1];
        NSMutableString * str = [NSMutableString stringWithString:@"1”];
        a.array = @[str, @"2", @"3”];
        ClassA * a2 = a.copy;
        [str appendString:@" hello”];
        NSLog(@"a: %@", a);
        NSLog(@"a2: %@", a2);

看看打印


image.png

就是我们之前说的单层深拷贝。如果想要实现完全复制,还是需要用到上面的解档和归档。

说到copy,很多面试都会问到一个问题,什么时候属性使用copy进行修饰?
对于拥有可变和不可变的类,如NSString,NSArray,NSSet等,修饰它们的不可变属性的时候,使用copy进行修饰。为什么呢?因为当用可变属性给不可变属性赋值的时候,可变值的修改会影响属性的值。看例子比较清楚。

我们新建一个类ClassB


image.png
image.png

测试:


image.png

看看结果:


image.png

用copy修饰的数组没有改变,用strong修饰的数组多了一个元素。

注意:

但是对于可变对象类型,如NSMutableString、NSMutableArray等则不可以使用copy修饰,因为Foundation框架提供的这些类都实现了NSCopying协议,使用copy方法返回的都是不可变对象,如果使用copy修饰符在对可变对象赋值时则会获取一个不可变对象,接下来如果对这个对象进行可变对象的操作则会产生异常,因为OC没有提供mutableCopy修饰符,对于可变对象使用strong修饰符即可。

本节学习了对象的可变性和浅复制,深复制,完全复制。

时间总是碎片化的,断断续续的整理了几天才把这几个知识点测试完。现在才知道,大块的时间真的是奢侈啊。抓住时间,努力学习,让生活变得更温柔。

源码地址:
https://github.com/weiman152/iOSTestCode/tree/master/iOS/Lesson9_Foundation

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容

  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,745评论 2 9
  • 重点掌握 3 类对象和方法 对象就是一个物体 类的独特存在就是一个实例,对实例进行操作叫做方法。方法可以应用于类或...
    Coder大雄阅读 1,257评论 0 2
  • 307、setValue:forKey和setObject:forKey的区别是什么? 答:1, setObjec...
    AlanGe阅读 1,539评论 0 1
  • ITEM 17: MINIMIZE MUTABILITY  不可变类就是一个实例不能被修改的类。每个实例中包含的所...
    rabbittttt阅读 268评论 0 0
  • 1.import static是Java 5增加的功能,就是将Import类中的静态方法,可以作为本类的静态方法来...
    XLsn0w阅读 1,219评论 0 2