這篇文章主要介紹“Java深拷貝與淺拷貝的區(qū)別是什么”,在日常操作中,相信很多人在Java深拷貝與淺拷貝的區(qū)別是什么問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Java深拷貝與淺拷貝的區(qū)別是什么”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!
創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的北林網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!如何區(qū)分深拷貝與淺拷貝,大白話來說,就是假設(shè)B復(fù)制了A,當(dāng)修改A時(shí),看B是否會(huì)發(fā)生變化,如果B也跟著變了,說明這是淺拷貝,拿人手短,如果B沒變,那就是深拷貝,自食其力。
先看一個(gè)例子:
let a = [0, 1, 2, 3, 4], b = a; console.log(a === b); // true a[0] = 9; console.log(a, b); // [9, 1, 2, 3, 4]
吆哈,明明b復(fù)制了a,為啥修改數(shù)組a,數(shù)組b也跟著變了??
基本數(shù)據(jù)類型和復(fù)雜(引用)數(shù)據(jù)類型?
基本數(shù)據(jù)類型:number, string, boolean, null, undefined, symbol
引用數(shù)據(jù)類型:Object類,有常規(guī)名值對(duì)的無須對(duì)象{a: 1}, 數(shù)組[1, 2, 3],函數(shù)等。
而這兩類數(shù)據(jù)存儲(chǔ)方式分別是這樣的:
1. 基本類型–名值存儲(chǔ)在棧內(nèi)存中,例如let a=1;
當(dāng)你b=a復(fù)制時(shí),棧內(nèi)存會(huì)新開辟一個(gè)內(nèi)存,例如這樣:
所以當(dāng)你此時(shí)修改a=2,對(duì)b并不會(huì)造成影響,因?yàn)榇藭r(shí)的b已自食其力,翅膀硬了,不受a的影響了。當(dāng)然,let a=1, b=a; 雖然b不受a影響,但這也算不上深拷貝,因?yàn)樯羁截惐旧碇会槍?duì)較為復(fù)雜的object類型數(shù)據(jù)。
2.引用數(shù)據(jù)類型–名存在棧內(nèi)存中,值存在于堆內(nèi)存中,但是棧內(nèi)存會(huì)提供一個(gè)引用的地址指向堆內(nèi)存中的值,我們以上面淺拷貝的例子畫個(gè)圖:
當(dāng)b=a進(jìn)行拷貝時(shí),其實(shí)復(fù)制的是a的引用地址,而并非堆里面的值。
而當(dāng)我們a[0]=1時(shí)進(jìn)行數(shù)組修改時(shí),由于a與b指向的是同一個(gè)地址,所以自然b也受了影響,這就是所謂的淺拷貝了。
那,要是在堆內(nèi)存中也開辟一個(gè)新的內(nèi)存專門為b存放值,就像基本類型那樣,豈不就達(dá)到深拷貝的效果了。
實(shí)現(xiàn)簡(jiǎn)單的深拷貝方法?
先看幾個(gè)簡(jiǎn)單例子?
1.slice() 方法
// 先看一個(gè)js中的方法slice() 方法可從已有的數(shù)組中返回選定的元素。 // 該方法并不會(huì)修改數(shù)組,而是返回一個(gè)子數(shù)組。arrayObject.slice(start,end) let a1 = [1, 2, 3, 4], b2 = a1.slice(); a1[0] = 2; console.log(a1, b2);
如上圖所述,slice()方法看似是一個(gè)深拷貝的方法了!在改造一下上述代碼片段,我們?cè)倏?????
let a1 = [1, 2, [5,6], 3, 4], b2 = a1.slice(); a1[0] = 2; a1[2][0] = 9; console.log(a1, b2);
拷貝的不徹底,b對(duì)象的一級(jí)屬性確實(shí)不受影響了,但是二級(jí)屬性還是沒能拷貝成功,仍然脫離不了a的控制,說明slice根本不是真正的深拷貝。
2.遞歸
// 簡(jiǎn)單深拷貝封裝遞歸函數(shù) function deepClone(obj) { let objClone = Array.isArray(obj) ? [] : {}; if (obj && typeof obj === "object") { for (key in obj) { if (obj.hasOwnProperty(key)) { // 注:hasOwnProperty()方法 //判斷obj子元素是否為對(duì)象,如果是,遞歸復(fù)制 console.log(obj[key]) if (obj[key] && typeof obj[key] === "object") { objClone[key] = deepClone(obj[key]); } else { //如果不是,簡(jiǎn)單復(fù)制 objClone[key] = obj[key]; } } } } return objClone; } let arr = [1, 2, [5, 6], 4], b1 = deepClone(arr); arr[2][0] = 9; console.log(arr, b1); // 跟之前想象的一樣,現(xiàn)在b脫離了a的控制,不再受a影響了。這里再次強(qiáng)調(diào),深拷貝,是拷貝對(duì)象各個(gè)層級(jí)的屬性。
注:hasOwnProperty() 官方 MDN講解方法會(huì)返回一個(gè)布爾值,指示對(duì)象自身屬性中是否具有指定的屬性(也就是,是否有指定的鍵)。
3. 除了遞歸,我們還可以借用JSON對(duì)象的parse和stringify。
function deepClone(obj){ let _obj = JSON.stringify(obj), objClone = JSON.parse(_obj); return objClone } let a=[0,1,[2,3],4], b=deepClone(a); a[0]=1; a[2][0]=1; console.log(a,b);
4. 除了上面兩種方法之外,我們還可以借用JQ的extend方法。
$.extend( [deep ], target, object1 [, objectN ] )
deep表示是否深拷貝,為true為深拷貝,為false,則為淺拷貝
target Object類型 目標(biāo)對(duì)象,其他對(duì)象的成員屬性將被附加到該對(duì)象上。
object1 objectN可選。 Object類型 第一個(gè)以及第N個(gè)被合并的對(duì)象。
let a=[0,1,[2,3],4], b=$.extend(true,[],a); a[0]=1; a[2][0]=1; console.log(a,b);
到此,關(guān)于“Java深拷貝與淺拷貝的區(qū)別是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!