一、数组的深浅拷贝
在使用JavaScript对数组进行操作的时候,我们经常需要将数组进行备份,事实证明如果只是简单的将它赋予其他变量,那么我们只要更改其中的任何一个,然后其他的也会跟着改变,这就导致了问题的发生。
var arr = [“One”,“Two”,“Three”];
var arrto = arr;
arrto[1] = “test”;
document。writeln(“数组的原始值:” + arr + “
”);//Export:数组的原始值:One,test,Three
document。writeln(“数组的新值:” + arrto + “
”);//Export:数组的新值:One,test,Three
像上面的这种直接赋值的方式就是浅拷贝,很多时候,这样并不是我们想要得到的结果,其实我们想要的是arr的值不变,不是吗?
方法一:js的slice函数
对于array对象的slice函数,
返回一个数组的一段。(仍为数组)
arrayObj。slice(start, [end])
参数
arrayObj
必选项。一个 Array 对象。
start
必选项。arrayObj 中所指定的部分的开始元素是从零开始计算的下标。
end
可选项。arrayObj 中所指定的部分的结束元素是从零开始计算的下标。
说明
slice 方法返回一个 Array 对象,其中包含了 arrayObj 的指定部分。
slice 方法一直复制到 end 所指定的元素,但是不包括该元素。如果 start 为负,将它作为 length + start处理,此处 length 为数组的长度。如果 end 为负,就将它作为 length + end 处理,此处 length 为数组的长度。如果省略 end ,那么 slice 方法将一直复制到 arrayObj 的结尾。如果 end 出现在 start 之前,不复制任何元素到新数组中。
var arr = [“One”,“Two”,“Three”];
var arrtoo = arr。slice(0);
arrtoo[1] = “set Map”;
document。writeln(“数组的原始值:” + arr + “
”);//Export:数组的原始值:One,Two,Three
document。writeln(“数组的新值:” + arrtoo + “
”);//Export:数组的新值:One,set Map,Three
方法二:js的concat方法
concat() 方法用于连接两个或多个数组。
该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
语法
arrayObject。concat(arrayX,arrayX,。。。。。。,arrayX)
说明
返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组。
var arr = [“One”,“Two”,“Three”];
var arrtooo = arr。concat();
arrtooo[1] = “set Map To”;
document。writeln(“数组的原始值:” + arr + “
”);//Export:数组的原始值:One,Two,Three
document。writeln(“数组的新值:” + arrtooo + “
”);//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;
}
将一个对象的引用复制给另外一个对象,一共有三种方式。第一种方式是直接赋值,第二种方式是浅拷贝,第三种是深拷贝。所以大家知道了哈,这三种概念实际上都是为了拷贝对象啊。
1、直接赋值
好,下面我们先看第一种方式,直接赋值。在Java中,A a1 = a2,我们需要理解的是这实际上复制的是引用,也就是说a1和a2指向的是同一个对象。因此,当a1变化的时候,a2里面的成员变量也会跟着变化。各位,请看下面的代码吧!
package interfaces。nesting;
/* 建立类 */
class Resume {
private String name; //姓名
private String sex; //性别
private int age; //年龄
private String experience; //工作经历
public Resume(String name, String sex, int age) {
this。name = name;
this。sex = sex;
this。age = age;
}
public void displayResume() {
System。out。println(“姓名:”+name+“ 性别:”+sex+“ 年龄:”+age);
System。out。println(“工作经历:”+experience);
}
}
public class MainClass {
public static void main(String[] args) {
Resume zhangsan = new Resume(“zhangsan”,“男”,24);
zhangsan。setExperience(“2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码复制”);
zhangsan。displayResume();
Resume zhangsan1 = zhangsan;
zhangsan1。setExperience(“2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等”);
zhangsan。displayResume();
zhangsan1。displayResume();
}
}
package interfaces。nesting;
/* 建立类 */
class Resume {
private String name; //姓名
private String sex; //性别
private int age; //年龄
private String experience; //工作经历
public Resume(String name, String sex, int age) {
this。name = name;
this。sex = sex;
this。age = age;
}
public void displayResume() {
System。out。println(“姓名:”+name+“ 性别:”+sex+“ 年龄:”+age);
System。out。println(“工作经历:”+experience);
}
}
public class MainClass {
public static void main(String[] args) {
Resume zhangsan = new Resume(“zhangsan”,“男”,24);
zhangsan。setExperience(“2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码复制”);
zhangsan。displayResume();
Resume zhangsan1 = zhangsan;
zhangsan1。setExperience(“2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等”);
zhangsan。displayResume();
zhangsan1。displayResume();
}
}
程序运行结果
[java] view plain copy print?
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码复制
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码复制
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等
在本程序中,生成了一份zhangsan的简历。之后又复制了一份简历zhangsan1,可见zhangsan1中工作经历发生变化时,zhangsan的工作经历也发生了变化。
2、浅拷贝
上面直接赋值的结果,有时候可能并不是我们所想要的。就像我们投简历的时候,可能会根据应聘公司的类型做出相应的调整,如果是投技术类的工作可能会偏技术一点;如果是投国企啊什么之类的,社会经历学生工作什么的可能也是很重要的一部分。所以我们不需要当我们修改一份简历的时候,所有的简历都变调。不然到时候投技术类的公司又得改回来。说了这么多,我们也就是希望,把a1赋值给a2之后,a1和a2能保持独立,不要互相影响。
实现上面想法之一的方法就是Object的Clone()函数了。在这里,我们需要了解clone()主要做了些什么,创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。
好,我们先看这一段话的前一部分,如果字段是值类型,则直接复制。如下面程序所示
[java] view plain copy print?
package interfaces。nesting;
/* 建立类,实现Clone方法 */
class Resume implements Cloneable{
private String name; //姓名
private String sex; //性别
private int age; //年龄
private String experience; //工作经历
public Resume(String name, String sex, int age) {
this。name = name;
this。sex = sex;
this。age = age;
}
public void setAge(int age) {
this。age = age;
}
public int getAge() {
return age;
}
public void setExperience(String experience) {
this。experience = experience;
}
public String getExperience() {
return experience;
}
public void displayResume() {
System。out。println(“姓名:”+name+“ 性别:”+sex+“ 年龄:”+age);
System。out。println(“工作经历:”+experience);
}
public Object clone() {
try {
return (Resume)super。clone();
} catch (Exception e) {
e。printStackTrace();
return null;
}
}
}
public class MainClass {
public static void main(String[] args) {
Resume zhangsan = new Resume(“zhangsan”,“男”,24);
zhangsan。setExperience(“2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴”);
zhangsan。displayResume();
Resume zhangsan1 = (Resume)zhangsan。clone();
zhangsan1。setAge(23);
zhangsan1。displayResume();
Resume zhangsan2 = (Resume)zhangsan。clone();
zhangsan2。setExperience(“2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码”);
zhangsan2。displayResume();
zhangsan。displayResume();
}
}
package interfaces。nesting;
/* 建立类,实现Clone方法 */
class Resume implements Cloneable{
private String name; //姓名
private String sex; //性别
private int age; //年龄
private String experience; //工作经历
public Resume(String name, String sex, int age) {
this。name = name;
this。sex = sex;
this。age = age;
}
public void setAge(int age) {
this。age = age;
}
public int getAge() {
return age;
}
public void setExperience(String experience) {
this。experience = experience;
}
public String getExperience() {
return experience;
}
public void displayResume() {
System。out。println(“姓名:”+name+“ 性别:”+sex+“ 年龄:”+age);
System。out。println(“工作经历:”+experience);
}
public Object clone() {
try {
return (Resume)super。clone();
} catch (Exception e) {
e。printStackTrace();
return null;
}
}
}
public class MainClass {
public static void main(String[] args) {
Resume zhangsan = new Resume(“zhangsan”,“男”,24);
zhangsan。setExperience(“2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴”);
zhangsan。displayResume();
Resume zhangsan1 = (Resume)zhangsan。clone();
zhangsan1。setAge(23);
zhangsan1。displayResume();
Resume zhangsan2 = (Resume)zhangsan。clone();
zhangsan2。setExperience(“2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码”);
zhangsan2。displayResume();
zhangsan。displayResume();
}
}
程序运行结果
[java] view plain copy print?
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:23
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:23
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴
由程序的运行结果可以看出,我们实现了a1和a2引用的独立。
但是什么叫“如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。”,到底什么意思?不用着急,我们接下来看下面一段程序:
[java] view plain copy print?
package interfaces。nesting;
class Experience {
private String educationBackground;
private String skills;
public void setExperience(String educationBackground, String skills) {
// TODO Auto-generated constructor stub
this。educationBackground = educationBackground;
this。skills = skills;
}
public String toString() {
return educationBackground + skills;
}
}
/* 建立类,实现Clone方法 */
class Resume implements Cloneable{
private String name; //姓名
private String sex; //性别
private int age; //年龄
private Experience experience; //工作经历
public Resume(String name, String sex, int age) {
this。name = name;
this。sex = sex;
this。age = age;
this。experience = new Experience();
}
public void setAge(int age) {
this。age = age;
}
public int getAge() {
return age;
}
public Experience getExperience() {
return experience;
}
public void setExperience(String educationBackground, String skills) {
experience。setExperience(educationBackground, skills);
}
public void displayResume() {
System。out。println(“姓名:”+name+“ 性别:”+sex+“ 年龄:”+age);
System。out。println(“工作经历:”+experience。toString());
}
public Object clone() {
try {
return (Resume)super。clone();
} catch (Exception e) {
e。printStackTrace();
return null;
}
}
}
public class MainClass {
public static void main(String[] args) {
Resume zhangsan = new Resume(“zhangsan”,“男”,24);
zhangsan。setExperience(“2009-2013就读于家里蹲大学”,“精通JAVA,C,C++,C#等代码拷贝和粘贴”);
zhangsan。displayResume();
Resume zhangsan2 = (Resume)zhangsan。clone();
zhangsan2。setExperience(“2009-2013就读于家里蹲大学”,“精通JAVA,C,C++,C#等”);
zhangsan2。displayResume();
zhangsan。displayResume();
zhangsan2。displayResume();
}
}
package interfaces。nesting;
class Experience {
private String educationBackground;
private String skills;
public void setExperience(String educationBackground, String skills) {
// TODO Auto-generated constructor stub
this。educationBackground = educationBackground;
this。skills = skills;
}
public String toString() {
return educationBackground + skills;
}
}
/* 建立类,实现Clone方法 */
class Resume implements Cloneable{
private String name; //姓名
private String sex; //性别
private int age; //年龄
private Experience experience; //工作经历
public Resume(String name, String sex, int age) {
this。name = name;
this。sex = sex;
this。age = age;
this。experience = new Experience();
}
public void setAge(int age) {
this。age = age;
}
public int getAge() {
return age;
}
public Experience getExperience() {
return experience;
}
public void setExperience(String educationBackground, String skills) {
experience。setExperience(educationBackground, skills);
}
public void displayResume() {
System。out。println(“姓名:”+name+“ 性别:”+sex+“ 年龄:”+age);
System。out。println(“工作经历:”+experience。toString());
}
public Object clone() {
try {
return (Resume)super。clone();
} catch (Exception e) {
e。printStackTrace();
return null;
}
}
}
public class MainClass {
public static void main(String[] args) {
Resume zhangsan = new Resume(“zhangsan”,“男”,24);
zhangsan。setExperience(“2009-2013就读于家里蹲大学”,“精通JAVA,C,C++,C#等代码拷贝和粘贴”);
zhangsan。displayResume();
Resume zhangsan2 = (Resume)zhangsan。clone();
zhangsan2。setExperience(“2009-2013就读于家里蹲大学”,“精通JAVA,C,C++,C#等”);
zhangsan2。displayResume();
zhangsan。displayResume();
zhangsan2。displayResume();
}
}
程序运行结果:
[java] view plain copy print?
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
我们看一下上面两段程序差异在哪儿,第一段程序的工作经历是作为Resume类的一个普通的成员变量,也就是值属性。而后面一段程序中,工作经历Experience是一个类。结合上面程序的运行结果,我们再来理解“如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。”其实也就是说,zhangsan和zhangsan2里面的Experience类指向的是同一个对象嘛!那不管是zhangsan里面的Experience变化,还是zhangsan2里面的Experience变化都会影响另外一个啊。
浅拷贝,大家懂没?Over了啊!
3、深拷贝
由前面的分析,浅拷贝无法实现含有其他对象引用的本对象的拷贝。那么很显然,深拷贝,就是说创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论该字段是值类型的还是引用类型,都乖乖的进行复制。
有了这个出发点,其实改起来很好改啊。浅拷贝的死穴就在于原始对象及其副本引用同一个对象,那我们让他们不指向同一个对象不就完了嘛!见代码:
class Experience {
private String educationBackground;
private String skills;
public void setExperience(String educationBackground, String skills) {
// TODO Auto-generated constructor stub
this。educationBackground = educationBackground;
this。skills = skills;
}
public String toString() {
return educationBackground + skills;
}
}
/* 建立类,实现Clone方法 */
class Resume implements Cloneable{
private String name; //姓名
private String sex; //性别
private int age; //年龄
private Experience experience; //工作经历
public Resume(String name, String sex, int age) {
this。name = name;
this。sex = sex;
this。age = age;
this。experience = new Experience();
}
public void displayResume() {
System。out。println(“姓名:”+name+“ 性别:”+sex+“ 年龄:”+age);
System。out。println(“工作经历:”+experience。toString());
}
public Object clone() {
try {
return (Resume)super。clone();
} catch (Exception e) {
e。printStackTrace();
return null;
}
}
}
public class MainClass {
public static void main(String[] args) {
Resume zhangsan = new Resume(“zhangsan”,“男”,24);
zhangsan。setExperience(“2009-2013就读于家里蹲大学”,“精通JAVA,C,C++,C#等代码拷贝和粘贴”);
zhangsan。displayResume();
Resume zhangsan2 = (Resume)zhangsan。clone();
zhangsan2。setExperience(“2009-2013就读于家里蹲大学”,“精通JAVA,C,C++,C#等”);
zhangsan2。displayResume();
zhangsan。displayResume();
zhangsan2。displayResume();
}
}
package interfaces。nesting;
class Experience {
private String educationBackground;
private String skills;
public void setExperience(String educationBackground, String skills) {
// TODO Auto-generated constructor stub
this。educationBackground = educationBackground;
this。skills = skills;
}
public String toString() {
return educationBackground + skills;
}
}
/* 建立类,实现Clone方法 */
class Resume implements Cloneable{
private String name; //姓名
private String sex; //性别
private int age; //年龄
private Experience experience; //工作经历
public Resume(String name, String sex, int age) {
this。name = name;
this。sex = sex;
this。age = age;
this。experience = new Experience();
}
public void setAge(int age) {
this。age = age;
}
public int getAge() {
return age;
}
public Experience getExperience() {
return experience;
}
public void setExperience(String educationBackground, String skills) {
experience = new Experience();
experience。setExperience(educationBackground, skills);
}
public void displayResume() {
System。out。println(“姓名:”+name+“ 性别:”+sex+“ 年龄:”+age);
System。out。println(“工作经历:”+experience。toString());
}
public Object clone() {
try {
return (Resume)super。clone();
} catch (Exception e) {
e。printStackTrace();
return null;
}
}
}
public class MainClass {
public static void main(String[] args) {
Resume zhangsan = new Resume(“zhangsan”,“男”,24);
zhangsan。setExperience(“2009-2013就读于家里蹲大学”,“精通JAVA,C,C++,C#等代码拷贝和粘贴”);
zhangsan。displayResume();
Resume zhangsan2 = (Resume)zhangsan。clone();
zhangsan2。setExperience(“2009-2013就读于家里蹲大学”,“精通JAVA,C,C++,C#等”);
zhangsan2。displayResume();
zhangsan。displayResume();
zhangsan2。displayResume();
}
}
程序运行结果:
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等代码拷贝和粘贴
姓名:zhangsan 性别:男 年龄:24
工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
如有不足之处,欢迎指正啊!最后,祝大家睡个好觉(⊙o⊙)哦!See you~~
简单的来说就是,在有指针的情况下,浅拷贝只是增加了一个指针指向已经存在的内存,而深拷贝就是增加一个指针并且申请一个新的内存,使这个增加的指针指向这个新的内存,采用深拷贝的情况下,释放内存的时候就不会出现在浅拷贝时重复释放同一内存的错误!
我列举一个例子来说吧:
你正在编写C++程序中有时用到,操作符的重载。最能体现深层拷贝与浅层拷贝的,就是‘=’的重载。
看下面一个简单的程序:
class string
{
char *m_str;
public:
string(char *s)
{
m_str=s;
}
string()
{};
String & operator=(const string s)
{
m_str=s。m_str;
return *this
}
};
int main()
{
string s1(“abc”),s2;
s2=s1;
cout<
}
上面的 =重载其是就是实现了浅拷贝原因。是由于对象之中含有指针数据类型。s1,s2恰好指向同一各内存。所以是浅拷贝。而你如果修改一下原来的程序:
string&operator=(const string&s)
{
if(strlen(m_str)!=strlen(s。m_str))
m_str=new char[strlen(s。m_str)+1];
if(*this!=s)
strcopy(m_str,s。m_str);
return *this;
}
这样你就实现了深拷贝,原因是你为被赋值对象申请了一个新的内存所以就是深拷贝。
- 上一篇:div 如果文字有多行,行间距怎么设置
- 下一篇:·格物致知是什么意思