java深拷贝和浅拷贝的区别,java clone是浅拷贝吗
大家好,如果您还对java深拷贝和浅拷贝的区别不太了解,没有关系,今天就由本站为大家分享java深拷贝和浅拷贝的区别的知识,包括java clone是浅拷贝吗的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!
深拷贝和浅拷贝的区别
一、概念
1、浅拷贝
浅拷贝只复制某个对象的引用,而不复制对象本身,新旧对象还是共享同一块内存
2、深拷贝
深拷贝会创造一个一摸一样的对象,新对象和原对象不共享内存,修改新对象不会改变原对对象。
二、方法
1、浅拷贝
a、Object.assign()
Object.assign()方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。Object.assign()拷贝的是对象的属性的引用,而不是对象本身。
2、深拷贝
a、JSON转换
let newObj= JSON.parse(JSON.stringify(obj))。
缺点:
1)如果对象有函数,函数无法被拷贝下来
2)无法拷贝对象原型链上的属性和方法
3)当数据的层次很深,会栈溢出
js深拷贝和浅拷贝的区别
1.浅拷贝:复制一份引用,所有引用对象都指向一份数据,并且都可以修改这份数据。
2.深拷贝(复杂):复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。
一、数组的深浅拷贝
在使用JavaScript对数组进行操作的时候,我们经常需要将数组进行备份,事实证明如果只是简单的将它赋予其他变量,那么我们只要更改其中的任何一个,然后其他的也会跟着改变,这就导致了问题的发生。
var arr= ["One","Two","Three"]; var arrto= arr; arrto[1]="test"; document.writeln("数组的原始值:"+ arr+"<br/>");//Export:数组的原始值:One,test,Three document.writeln("数组的新值:"+ arrto+"<br/>");//Export:数组的新值:One,test,Three
像上面的这种直接赋值的方式就是浅拷贝,很多时候,这样并不是我们想要得到的结果,其实我们想要的是arr的值不变,不是吗?
方法一:js的slice函数
var arr= ["One","Two","Three"]; var arrtoo= arr.slice(0); arrtoo[1]="set Map"; document.writeln("数组的原始值:"+ arr+"<br/>");//Export:数组的原始值:One,Two,Three document.writeln("数组的新值:"+ arrtoo+"<br/>");//Export:数组的新值:One,set Map,Three
方法二:js的concat方法
var arr= ["One","Two","Three"]; var arrtooo= arr.concat(); arrtooo[1]="set Map To"; document.writeln("数组的原始值:"+ arr+"<br/>");//Export:数组的原始值:One,Two,Three document.writeln("数组的新值:"+ arrtooo+"<br/>");//Export:数组的新值:One,set Map To,Three
二、对象的深浅拷贝
var a={name:'yy',age:26}; var b=new Object(); b.name=a.name; b.age=a.age; a.name='xx'; console.log(b);//Object{ name="yy", age=26} console.log(a);//Object{ name="xx", age=26}
就是把对象的属性遍历一遍,赋给一个新的对象。
var deepCopy= function(source){ var result={}; for(var key in source){ result[key]= typeof source[key]==='object'? deepCoyp(source[key]): source[key];} return result;}
举一个jQuery中的例子:
jQuery.extend= jQuery.fn.extend= function(){//1.将extend方法扩展到JQ(函数)下边:扩展静态方法//2. jQuery.fn.extend把extend扩展到jq.fn下且jQuery.fn= jQuery.prototype扩展实例方法// 1.2.功能相似 var options, name, src, copy, copyIsArray, clone,//定义一些变量 target= arguments[0]||{},//目标元素是【0】第一个元素$.extend( a,{ name:'hello'},{ age: 30}); i= 1,//第一个元素的位置 length= arguments.length,//第一个个对象的元素 deep= false;//是否是深拷贝默认 false不是// Handle a deep copy situation看是不是深拷贝情况 if( typeof target==="boolean"){//是布尔值 deep= target; target= arguments[1]||{};//目标元素是第二个$.extend( true, a, b)// skip the boolean and the target i= 2;}// Handle case when target is a string or something(possible in deep copy)看参数正确不 if( typeof target!=="object"&&!jQuery.isFunction(target)){//当目标不是对象或者不是函数的时候 target={};//变成一个空的jason}// extend jQuery itself if only one argument is passed看是不是插件情况 if( length=== i){//只写了一个对象要把这个对象扩展到jq源码上静态方法或者是实例方法 target= this;//this是$或者$();--i;}//可能有多个对象情况 for(; i< length; i++){// Only deal with non-null/undefined values if((options= arguments[ i ])!= null){//看后边的对象是否都有值// Extend the base object for( name in options){ src= target[ name ]; copy= options[ name ];// Prevent never-ending loop if( target=== copy){//防止循环引用 continue;//跳出本次循环继续执行//$.extend( a,{ name: a}));循环引用 a也是一个对象}// Recurse if we're merging plain objects or arrays深拷贝 if( deep&& copy&&( jQuery.isPlainObject(copy)||(copyIsArray= jQuery.isArray(copy)))){//是深拷贝且需有var b={ name:{ age: 30}};且b必须是对象自变量(jason)或者是个数组//递归 if( copyIsArray){//数组 copyIsArray= false; clone= src&& jQuery.isArray(src)? src: [];//定义一个空数组} else{//jason clone= src&& jQuery.isPlainObject(src)? src:{};//看原有的属性有没有且是不是jason定义一个空jason}// var a={ name:{ job:'it'}};看有没有原有的属性有的话在原有的上边添加// var b={ name:{age: 30}};//$.extend( true, a, b);//a继承b// console.log( a); a{ name:{ job:'it',age: 30}}如果只有一个{}则只有,age: 30// Never move original objects, clone(a) them target[ name ]= jQuery.extend( deep, clone, copy);//调用函数本身进行进一步的递归处理// Don't bring in undefined values浅拷贝} else if( copy!== undefined){ target[ name ]= copy;//直接复制因为里边没有对象}}}}// Return the modified object return target;};
深拷贝和浅拷贝的理解
深拷贝和浅拷贝的核心区别在于对对象内部引用类型的处理方式:深拷贝会递归复制所有嵌套对象,生成完全独立的副本;浅拷贝仅复制对象第一层的属性,嵌套对象仍共享引用。以下是具体分析:
一、基础概念解析浅拷贝
定义:仅复制对象的第一层属性,若属性值为引用类型(如对象、数组),则复制的是引用地址而非实际数据。
特点:
修改拷贝对象的基本类型属性(如数字、字符串)不会影响原对象。
修改拷贝对象的引用类型属性(如嵌套对象、数组)会同步影响原对象,因为两者指向同一内存地址。
实现方式:
JavaScript中可通过Object.assign()、展开运算符{...obj}或数组的slice()、concat()实现。
示例:
const original={ a: 1, b:{ c: 2}};const shallowCopy={...original};shallowCopy.b.c= 3;//原对象original.b.c也会变为3深拷贝
定义:递归复制对象的所有层级,包括嵌套的引用类型,生成完全独立的副本。
特点:
修改拷贝对象的任何层级属性均不会影响原对象。
需要处理循环引用等特殊情况,否则可能导致栈溢出。
实现方式:
递归实现:手动遍历对象属性,对每个引用类型属性递归调用深拷贝。
JSON方法:通过JSON.parse(JSON.stringify(obj))实现,但会忽略函数、Symbol、undefined等特殊类型。
第三方库:如Lodash的_.cloneDeep()。
示例:
function deepClone(obj){ if(typeof obj!=='object'|| obj=== null) return obj; const clone= Array.isArray(obj)? []:{}; for(let key in obj){ clone[key]= deepClone(obj[key]);//递归复制} return clone;}const original={ a: 1, b:{ c: 2}};const deepCopy= deepClone(original);deepCopy.b.c= 3;//原对象original.b.c仍为2二、关键问题澄清“深拷贝通过递归实现赋值”的原理
递归会逐层检查对象属性,若属性为引用类型,则继续向下复制直到所有层级均为基本类型。
例如,复制{ a:{ b:{ c: 1}}}时,递归会先复制外层对象,再复制a属性指向的对象,最后复制b属性指向的对象。
“for循环数组相当于深拷贝”的误区
错误原因:
若数组元素为基本类型(如数字、字符串),for循环复制确实会生成独立副本,因为基本类型按值传递。
但若数组元素为对象或数组,for循环仅复制引用地址,仍属于浅拷贝。
示例:
const originalArr= [{ a: 1},{ b: 2}];const copiedArr= [];for(let i= 0; i< originalArr.length; i++){ copiedArr.push(originalArr[i]);//仅复制引用}copiedArr[0].a= 3;//原数组originalArr[0].a也会变为3“变量赋值与拷贝无关”
基本类型(如let a= 1; let b= a)的赋值是按值传递,生成独立副本,但这不是拷贝的范畴。
拷贝仅针对对象或数组等引用类型,因为它们的赋值是按引用传递。
三、面试题常见考点内存分配差异
浅拷贝:原对象与拷贝对象共享嵌套对象的内存地址,修改会相互影响。
深拷贝:所有层级均分配新内存,修改互不影响。
内存图示例:
浅拷贝:原对象和拷贝对象的第一层属性指向不同内存,但嵌套对象指向同一内存。
深拷贝:所有层级属性均指向新分配的内存。
性能权衡
浅拷贝速度快,适合无嵌套对象的场景。
深拷贝速度慢(需递归遍历),但能保证数据完全独立。
特殊场景处理
循环引用:对象属性间接或直接引用自身,需通过WeakMap记录已复制对象避免无限递归。
非JSON安全类型:如函数、Date对象,需自定义深拷贝逻辑。
四、总结浅拷贝适用于简单对象或明确无需独立嵌套对象的场景。深拷贝适用于需要完全隔离数据的复杂对象,但需注意性能和循环引用问题。核心判断方法:修改拷贝对象的嵌套属性,观察原对象是否变化——若变化则为浅拷贝,否则为深拷贝。
关于java深拷贝和浅拷贝的区别,java clone是浅拷贝吗的介绍到此结束,希望对大家有所帮助。