00:00
我们给大家演示一个深拷贝的案例,大家看看深拷贝是怎么实现的,两种方式呢?都给大家演示一下好,OK deep。Deep阁楼。深拷贝,那深拷贝首先呢,我得有一个类,我把它准备好了,同学们看我这里有这么一个叫做deep。Target。这个呢,我们就直接拿来用一下,好不好,就直接拿来用一下,OK。那现在呢,我们在这儿写一个这样的类。叫deep。Target。那么这个类里边呢,假如说我们这有这,因为这比较简单,我就直接拿来用了,这个大家都能看懂哈,没有哪个同学看不懂的。大家看,然后呢,我让他去实现两个接口。实现两个接口,一个就是server,一个是可能able。那大家可以看到在这里呢,我是这么来设计,在这个地方要引下。
01:01
OK。嗯,哪个呢,第一个。嗯,就是说在地铺。C这个target这个类里面呢,它有两个数据类型,呃,两个属性都是实最类型的,一个是名字,一个是c class就随便设置的哈。然后这是它的构造器,同学们可以看到这是它的构造器,没问题吧?这个地方,嗯,因为它的两个,它的两个属性呢,都是字符串。所以说我这里这个克隆呢,我就直接用的是默认的克隆方法,我们前面讲过,默认的这个克隆方方法呢,它会对字基本数据类型和字符串呢进行一个拷贝,这个是没问题的。所以说这里呢,因为。我说了啊,因为该类该类的。这个属性啊,都是string。因此呢,因此我们这里这里使用什么呀,默认的默认的克隆方法完成即可。
02:03
完成即可。好的,这个大家应该能看懂对不对,好,下面呢,我们来写我们这个这个地。第一步的这个,呃,原型原原原型类型就是我们现在写这么一个类。Deep。第一步什么呢?Proto type。OK,这个类,那这个类呢,我们里面给他设计这么一些东西,它既有基本数据类型,也有什么呢?也有这个就是它也有引用类型,首先我们仍然让他也实现那两个接口,一个是S。这个没问题,对不对,还有一个CC。好的。然后呢,同学们可以看到在这里我们设置这么几个属性,大家跟上我的思路都比较简单啊,Name,这是它的一个字符串属性。还有一个OK,还有一个什么呢,我们写一下public。
03:01
就是刚才我们写的这个这个类就deep c targets,同样呢,我们给他一个名字,简单一点就用这个好,显然这是一个引用,引用类型的属性。引用类型。好的。好,这边少了一个分号。没问题了,同学们。那有了这两个属性过后呢,我们首先还是提供一个构造方法,对不对构造方法。这割断方法呢,这里面我都不要啊,就用一个默认的空的割断,割断方法就完事了,下面呢,我们来对它进行一个呃声,我们来完成什么呢?完成这个深拷贝。深拷贝实现。啊。呃,深拷贝吧,深拷贝。那身高贝,我们先写方式一。方式,我们讲的有两种方式,对不对,我们方式一呢,使用什么呢?使用克隆的方法。使用克隆。就是相当于重写克隆方法。
04:02
克隆法C对吧,没问题,克隆方法。来跟着老师思路,那我开始写了,呃,克隆方法呢,那我就重写一下,我就写克隆。克隆。OK,重写一下,那在这里呢,我怎么去完成这个处理呢?因为大家可以看到啊。我们我们是这样来完成的,首先呢。我先写个object。对不对,Deep,这个是我将来要返回的对象,要生成对象,要生成对象TRY。那这个地方我们我们这样来做地铺这一块。地这块。他。他首先让这一个默认的这个方法来完成一个处理,就是super点。哎,这叫super克就调不出来啊,复制一份。Super克隆。好,大家看这个地方,我们第一步。
05:03
第一步先用什么呢?这里写上啊,这里完成,对对,基本数据类型,当然应该叫基本数据类型,就是我们属性。属性啊的一个克隆。克隆。当然这个也包括了字符串啊,当这个基本数据类型,还有这个字符串和字符串的。这个没问题是吧,然后下边呢,我们要来单独的处理一下什么呢,同学们看这个返回的肯定是离了。把这个换一下。对,幻想你这样做。相当于没有做处理,所以说现在要单独的处理一下deep able target这个引用类型,那现在我们来写吧。来走一个啊,现在呢,我们对引用引用类型的属性进行单独的处理。
06:00
哎,单独处理。单独。处理。OK,跟上我的思路,那这个怎么来单独处理呢?首先。首先同学们,我们先创建,我们先整一个地。Target啊,就是deep。Deep的。Deep。就是这这个类型吧,先把这个类型拿出拿过来。走一个deep。那这个类型我会怎么来处理呢?大家想哈。因为我在前面已经有了一个这样的地图,所以说我把它先转成。Deep。Protocol type。这个大家能理解吧,就说你前面已经把基本数据处理,基本数据类型处理完了吗?然后呢,我把它转成它的一个子类,因为你这是object,我把它转成一个子类是没问题的。那转成子类以后,下面呢,Deep。Prototype它的哪一个呢?我们来处理一下,就是deep target,这是它的引用类型,对不对,你还没有处理,等于什么呢?单独的处理一下就可以了。
07:10
呃,这时要处理的话呢,也很简单,我们只需要这样做就可以了,怎么处理大家想。是不是我们用地?点调它的克隆,因为deep table这个这个这个对象呢,它里面有克隆方法。点什么呀,哎,这个我看看是啊,这已经做完了。这这个克隆就做完了,把它克自己克隆一下交给他,然后类型不匹配怎么办?把这个类型我们转一下就可以了,怎么转。把它转成。这样一个类型。转成deep。哦,转成他的自己的这个,我看这个类型这。啊,转成这样一个类型。转成地铺。
08:02
这个类型。OK,大家看这个能理解吧,就是说。我先把基本数据类型处理了。然后呢,再单独把这个地转成地。呃,Pro,呃,Protocol type,然后这里面呢,有一个deep target没有处理,我再单独单独的克隆一下给他就完事了。啊就完事了,但是类型呢,要转一下,是不是类型要转一下,好,那么这个代码处理完了过后呢,同学们可以看到。同学们可以看到,此时此刻我们这一个类型,就是同学们看到的哪一个类型呢?就是我们要返回的就它。这就是处理过后的了。也就是我们单独的先处理基本数据的类型,再处理引用类型就完事了。当然同学们可能会想到。如果说我们这个引用类型很多,像这样处理是不是有点麻烦的,是的是这样子的啊,就是因为你你这个引用类型要单独处理,没有办法明白吗?好,我们来试用一下,看看这种方式能不能。
09:07
能不能进行这个深拷贝呢?来,我们写段代码来进行一个小小的测试。来,同学们,我们。写一个client。C。把主方法给勾上,把主方法勾上,那主方法勾上过后呢,我们来测一下来同学们看。首先呢,我六一个地。又一个deep prototype。这个没问题,创建起来了。然后呢,我给他。呃,我给他一些信息,Deep port,点他的名字,我给他一个。但他是有名字,比如叫做宋江。啊,叫宋江。然后呢,我们再给他。就是地这个地方这个名字我们叫P吧,啊不要因为后面还有一些名字太长了P,那这个地方呢,P点它有一个这个类型叫deep global target是吧,是个引用类型,等于什么呢?我们直接溜一个。
10:08
又一个deep。好,这里面也有两个信息,一个比如说我们叫做。呃,比如他他这边有个信息叫做。呃,叫做看看取个什么名字啊,比如说随便写个啊,比如大牛。大牛,然后这个类。写一个。写个啊,比如说这个名字叫什么呢?大牛,他的大牛的外号叫做叫做什么呢。大牛的外号,比如说叫做,它有个类叫大牛类。大牛。的这个。你大牛的一个类对应的一个类。好了。这样呢,我们就把这个做好了,做好以后下面呢,我们做这样一件事情哈,做什么事情,我们用方式一方式一来进行这个呃,深拷贝啊,我们通过这个。
11:03
方式一来看看这个拷贝能否。得到一个。执行好方式一完成,完成这个深拷贝。深拷贝。那怎么用呢?同学们可以看到现在呢,我们这儿已经有一个P了,是吧,这个P里边是不是有一个方法叫克隆。是这样子的吧,克隆好,那在克隆以后我们。返回的这个类型,大家可以看到,返回类型呢,我们要把转成这种类型,就是deep步proto proto type这个类型,这个大家能理解哈,走写到这来,比如说我们有个P2等于它,当然我这要强转一下。相传一下。那强断电膜为什么抛错呢?因为我们这有个异常没有处理,所以说我简单一点呢,就直接把这个异常扔出去就可以了,我不管那么多哈,把扔出去扔出去过。现在我们来看P和P1。
12:02
P和P1他们的这一个引用类型。的哈希扣的是不是一样的,理论上说就不应该一样了,对不对,我执行一下。那首先呢,PEP的内蒙。等于我们把它打出来。再来看。P的这一个地。可能可能,呃,Target它的哈希code打出来。好,他的这个哈,Code我就直接这样输好不好就P点。这个东西点哈code打出来。同样道理,同样道理,我们再把P2也打出来一下,P2。P2P2,好,同学们想。名字肯定都一样,因为你这地方是克隆过的,所以说都宋江。那么现在呢,Deep可呃可target呢,他们的信息都是大牛和大牛的类啊,那这几个叫小牛吧,啊,小牛无所谓啊,这个小牛。
13:08
OK,那这个两个哈希扣的到底一样吗?显然它不一样了,我们来执行一下,可以看到的确不一样,所以说就实现了我们这一个。所谓的深拷贝,这是第一种方式,那么我们再来看第二一种方式,第二种方式呢,它相对来说哈比。这个第一种方式,呃,写起来麻烦,但是用起来方便,我们来看看这个时候怎么去写,打开这个地方,我们仍然在这来写,第二种方式来完成。写下要深拷贝。那么这是我们的方式二,方式二使用什么方式呢?同学们,我们通过序列化来完成这个的处理,来写到这来就是通过对象的序列化,序列化实现这个声拷贝。
14:01
这个方式呢,是给大家推荐的,就推荐使用。推荐大家使用,OK,那我开始写了哈,嗯,怎么写,那写一个我们写一个方法,返回public,返回一个object。那这帮我起个名字叫deep克隆。Deep克隆C、地克隆。那这个代码呢,我们怎么来完成哈,首先我们要,呃,因为整个这个处理的时候要用到序列化,那跟我们对象相关,所以说我要先要创建,创建什么呢?创建一些流对象。留对象,大家一会儿就知道我要干什么了。带字节流对象,字节数组输出。二。Output string。那么写上叫bos等于空。这是一个。待会儿我要用,我先写到这儿,还有一个object。Object也是一个输出流,Output output。
15:06
什么呢?也是一个string,好,我起个名叫OS为空。那还有一个什么呢?有输输出流就应该有输入流,对不对,那么同样道理,BA。什么呢?Input stream。那这个时候这个流呢,我们叫做B。BIS空同样也有对象的一个什么呀,对象的一个输入流,Input stream。然后呢,O。Is领空。好的,那现在我把这里面的该用的包呢,我们把它引进去。好,引进去就可以了,那有了这样几个类,我要干什么呢?这是输出流,这是输入流。以字节数组的OK字节数组和对象。的这这种流。那下面我要做一个处理,同学们看一看一下我要怎么处理,我先try catch一下,因为待会呢可能会有异常抛出,所以说我先try catch。
16:07
第一步,我们先来这样做,先来做序列化的操作。虚拟化。怎么怎么序列化呢?同学们看到bos这个,我要六一个对象叫BY。对,Bit output stream这个没问题,因为刚才只是定义了嘛,这是创建。这是输,呃输出的啊,这是输出的,当然OS等于什么呢?六一个object输出输输出流。对,这个有拿到。那这个流达到了,我们要把bos放进去,也就是说我们把这一个字节数组输出流换成了一个对象输出流。我要干什么呢?我要做这样一个工作,看啊同学们看到我有个os.right输出了,把谁输出呢?把这个this,诶同学们看明白我我要干什么事了吧。我把当前这个对象一。
17:07
对象流的方式,就是把当前这个对象Z这个对象与对象流的。方式输出。OK,其实就是我们所说的序列化,那么你把输出过去过后,你输出的时候,其实它会把你这里面所有的,包括你因为这个瑞,他在输出的时候呢,你如果这里面有引用类型,它也会输出去,是不是这个道理?好,现在我要进行一个反序列化。反序列化,那反序列化其实就是反其道而行之,那叫BI do读入,那读入呢,我肯定要有一个bit。这个输入,那这里面会算什么把bos。bo.two by,那这句话大家知道我在做什么事情吗?因为你这个输出流。
18:04
输出流,输出去过后,我再反复的把它读进来,读进来其实就相当于。把我们这个对象进行了一个克隆,是不是道理,那然后呢,这边是o is等于六,一个object,一个输入对象的一个枢纽,同样我们把它关联起来,BIS。是不是让BSOK,好,这样子o is呢,就读到了你原先序列化出去的这这个对象,也就是this对象。好,其实同学们可以看到,此时此刻,我们这个。O is呢,就可以read一个object,这方应该这个read object就是相当于把你这个对象先输出去,我又再读回来,读的时候呢,以对象的时候读的,这样就相当说我用序列化这个特点。把你关联的引用的这个类型也输出去,然后再回来的时候,自然他就会给你拷贝一份。
19:02
是不是这个道理好读出来过后这个对象就是我们要的哪个呢?Deep?就是我们这个对象了。哎,就是第一步prototype prototype。来,把它写到这来。走,那这个地方我们就写一个叫deep,呃,就叫copy吧,就叫我们copy的一个对象。等于他。那当然这个类型呢,因为你返回是个object,这边呢是deep prototype,因此我需要强转。所以同学们有没有发现我这段代码是在干什么呢?就是充分利用我们序列化和反序列化,把这个当前对象以对象流的方式输出去。然后再与对象的方式再读回来,诶一书一读,那么你这关联的引用类型也出去了,也读回来了,那这样子就很方便了,因为我就不用一个一个的处理,因为我是对this这个对象作为整体进行处理的,最后return谁呀?
20:02
这个copy过后的object代码就写完了。那就行,那么最后你不要忘了一件事情,因为你在这做的过程中呢,这有可能会有一个异常信息把它打出来。对吧,把它打出来,呃,打出个信息,同时如果有这样一个信息,我们就return一个空了,如果真的发生了一个catch catch到一个异常,那说明我们这个对象呢?嗯,可能是在序列或者反修出了问题,就一个空就完了,最后不要忘了一件事情,Finally。还要还要干什么事情,同学们知道吗?就是我们要把打开的流关闭掉,关闭流。是这意思吧,关闭流的时候是不是又可能抛出一个异常,于是还要出来catch一下,那就按照我们这个顺序来关闭就可以了,bos.close。对不对,然后呢是os.close对不对,然后是我们的bi.close对不对,然后还有一个最后一个OIs.close对不对,好,最后这个就是,当然这如果有异常信息呢,我们也把它进行一个处理就可以了,好吧,就是输出来就行。
21:06
那么我这里system。一二.get message完事了。好,同学们可以看到这段代码我们就写完了,就写完了,也就是说方式呢,是通过对象的序列化和反序化实现的,推荐使用,那这个方法能不能用呢?不知道,我们来玩一把好玩一把来走一个。那现在呢,我们呃,再来玩一把。现在我们写方式二。方式二,完成这个声拷贝。完成生。深拷贝没问题吧,同学们,嗯,那这样子啊,因为我也不想去比举别的例子了,就把上面这个代码先注销我们。重新来调就行了,这时呢?这个时候我们调的方法就是不是P点克隆了,而是P点地点克隆。因为这是我自己写的方法嘛,没问题吧,好呃,同学们可以看到呢,现在呢,我用的是地步克隆方法来克隆谁呀,克隆P本身。
22:10
那克隆完了个P2也有拿到了,然后呢,我们仍然输出他们的名字,还有们的引用类型,是不是呃,被也被克隆了。那当然名字还是宋江,然后他的这个哈希扣呢,应该是不一样的才对,来执行一下。好,同学们可以看到诶,我们看到名字仍然是宋江,同学们看到通过这种方式呢,拿到的哈西扣的也是不一样的,说明通过这一个啊,深度克隆我们的引用类型所指向的对象也被克隆了。那同学们可以可以一比较就知道这种方式肯定会更好一些,因为呃,这里面如果说它有除了有这种引用类型,比如说还有别的引用类型,是不是我一次就搞定了,因为我是把这个this当成一个整体来处理的,如果按照第一种方式,你的一个个处理太累了。
23:06
所以说同学们,我们推荐大家呢,使用我们讲的这种方式。这种方式。OK同学们,那关于我们原型模式里面涉及到的声拷贝这个应用案例呢,就给大家讲到这里,大家看理解了没有啊,就是代码这些都写完了啊,都写完了应该还是能够理解,是不是能够理解?OK,关于深拷贝就聊到这里。
我来说两句