作者:林冠宏 / 指尖下的幽灵

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

博客:http://www.cnblogs.com/linguanh/

GitHub : https://github.com/af913337456/

联系方式 / Contact:913337456@qq.com


了解这些术语:

  • 深复制又称深拷贝,两个变量的内存地址不一样,各自修改不影响对方。
  • 浅复制又称浅拷贝,两个变量的内存地址一样,既是同一个变量,仅仅是引用不同罢了,各自修改是会影响对方的,因为本身就是同一个。

这篇文文我要讲的有:

  • System.arraycopy 是深复制
  • System.arraycopy 的陷阱点
  • 对象引用对象 的区别
  • 简历不要写 精通java,写 熟练

首先明确一点,System.arraycopy 操作的是数组,效果是深复制。 是不是觉得怎么和你印象的中不一样?

重点来了,对于对象数组,例如: User[],这种数组,有一个注意点,这个点就是:对于数组内的对象是浅拷贝。

一句话:

  • System.arraycopy 对于数组是深拷贝,对于数组内的对象是浅拷贝。因为操作的传入参数是数组,那么回归本意,效果是深复制。

上面的含义一定要区分清楚! 因为现在网上很多观点是混淆,乱JB写的

来看个例子,下面的代码可以自己去运行验证。已经充分验证了上面我的观点。

public class Test {
public static void main(String[] args) { User[] users=new User[]{
new User("111"),new User("222"),new User("333")
};//初始化对象数组
User[] target=new User[users.length];//新建一个目标对象数组 System.arraycopy(users, 0, target, 0, users.length); // 复制 System.out.println("数组地址是否一样:"+(users == target?"浅复制":"深复制"));
System.out.println("数组内对象地址是否一样:"+(users[0] == target[0]?"浅复制":"深复制")); target[0].setEmail("444");
System.out.println("修改后输出 users[0] ,是否和 target[0]一样是444,users[0]:"+users[0].getEmail()); users[0] = null; // -----------------①
System.out.println("遍历 users");
for (User user : users){
System.out.println(user);
}
System.out.println("遍历 target");
for (User user : target){
System.out.println(user);
} users = null;
if(target == null){
System.out.println("users = null 后是否 target 也变成了 null,是则证明是浅复制");
}else{
System.out.println("users = null 后是否 target 不受任何影响,是则再次证明数组是深复制");
}
}
}
class User{
private String email;
public User(String email) { this.email = email; }
public String getEmail() { return email;}
public void setEmail(String email) { this.email = email; }
@Override
public String toString() { return "User [email=" + email+ "]"; }
}

输出的结果如下:

数组地址是否一样:深复制
数组内对象地址是否一样:浅复制
修改后输出 users[0],是否和 target[0]一样是444,users[0]:444
遍历 users
null
User [email=222]
User [email=333]
遍历 target
User [email=444]
User [email=222]
User [email=333]
users = null 后是否 target 不受任何影响,是则再次证明数组是深复制

上面我的例子还留有一个经典的面试点,既是标号 ① 对应的行:

users[0] = null; // -----------------①

上面我们谈到了,数组内的对象是浅复制,那么在上面这行我把 users[0] 下标为0的对象弄为 null 后。后面再遍历输出:

System.out.println("遍历 users");
for (User user : users){
System.out.println(user);
}
System.out.println("遍历 target");
for (User user : target){
System.out.println(user);
}

明显地,我们可以容易知道,user[0] 此时输出的肯定是 null。那么 target[0] 呢?浅拷贝的话,target[0] 必然在内存地址和值上面全等于 users[0]

但是从 System.out.println("遍历 target"); 的结果来看。却发现 target 输出的是:

遍历 target
User [email=444] // 第一个不是 null
User [email=222]
User [email=333]

这是为什么呢?其实这是最为基础的: 对象引用与对象的区别,一名合格,仅仅是合格的 Java 语言使用者,这个得知道。下面我们来谈谈它。

有一个类:

public class Demo {
//默认构造方法
public Demo{
}
}

我们用它创建个对象

Demo fuck = new Demo();

这一条语句,其实包括了四个动作:

  • 右边的“new Demo”,是以Demo类为模板,在堆空间里创建一个Demo对象。
  • 末尾的()意味着,在对象创建后,立即调用Demo类的构造函数,对刚生成的对象进行初始化。
  • 左边的“Demo fuck”创建了一个Demo类引用变量,它存放在栈空间中。也就是用来指向Demo对象的对象引用。
  • “=”操作符使对象引用指向刚创建的那个Demo对象。对象引用的名字叫做 fuck
Demo fuck;//一个对象引用
fuck = new Demo();//一个对象引用指向一个对象

一个对象可以被多个对象引用同时引用。它们操作的始终是同一个。

Demo fuck,fuck2;//创建多个对象引用
fuck = new Demo();
fuck2 = fuck;

好了,回答之前的坑, users[0] = new User("111")users[0] = nulltarget[0] = users[0],users[0] = null 只是把栈中的 users[0] 对象引用弄为了 null,对象 new User("111") 与它无关,自然没影响,target[0] 是另外一个对象引用,也是指向了 new User("111")。

根据 大 Jvm 的 内存回收算法之根搜索,引用链存在、强引用、when 当前应用内存不够了,强制抛出 OOM。那么当 target[0] = nullnew User("111") 对应的这块内存就会进入被回收的队列中,“死去”。

最后这段是不是有点看不懂 ?那证明你要继续努力了。

由 System.arraycopy 引发的巩固:对象引用 与 对象 的区别的更多相关文章

  1. 002-jdk-数据结构-工具类Collections、Arrays、System.arraycopy

    常用备注 一.LIst to Array List<String> list = new ArrayList<String>(); Object[] array=list.to ...

  2. System.arraycopy() 数组复制方法

    一.深度复制和浅度复制的区别    Java数组的复制操作可以分为深度复制和浅度复制,简单来说深度复制,可以将对象的值和对象的内容复制;浅复制是指对对象引用的复制. 二.System.arraycop ...

  3. System.arraycopy()和Arrays.copyOf()的区别

    先看看System.arraycopy()的声明: public static native void arraycopy(Object src,int srcPos, Object dest, in ...

  4. 求System.arraycopy的用法

    public class Shuzufuzhi { public static void main(String args[]) {  int myArray[]={1,2,3,4,5,6};  in ...

  5. System.arrayCopy()和普通数组复制之间的效率差别

    都是System.arrayCopy() 效率高,到底有多高呢,拉出来遛遛就知道了: package JCF.ArrayList; import java.util.Date; public clas ...

  6. java System.arraycopy 数组复制和合并

    public class Test { public static void main(String[] args) { Integer[] a = {1,2,3}; Integer[] b = {4 ...

  7. Exception raised during rendering: java.lang.System.arraycopy([CI[CII)V

    最近下载一个新版本的adt-bundle,Android API是20. 把Plain Text控件往布局上面拖时,发现拖不上去,出现了下面的错误: Exception raised during r ...

  8. Java数组的复制Arrays.copyOf()、System.arraycopy()、nums.clone()

    public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); a ...

  9. java的system.arraycopy()方法

    java.lang.System的静态方法arraycopy()可以实现数组的复制,讲课的老师说这个方法效率比较高,如果数组有成千上万个元素,那么用这个方法,比用for语句循环快不少.于是我试了试,发 ...

随机推荐

  1. Weave 如何与外网通信?- 每天5分钟玩转 Docker 容器技术(66)

    上一节我们学习了 Weave 网络内部如何通信,今天讨论 Weave 如何与外界通信. weave 是一个私有的 VxLAN 网络,默认与外部网络隔离.外部网络如何才能访问到 weave 中的容器呢? ...

  2. Project 3:N级魔方阵

    魔方阵:由n*n个数字所组成的n阶方阵,具有各对角线,各横列与纵行的数字和都相等的性质,称为魔方阵.而这个相等的和称为魔术数字.若填入的数字是从1到n*n,称此种魔方阵为n阶正规魔方阵. 目标:输入一 ...

  3. 学习Python Day1

    学习PythonDay1,主要是学习了循环,while循环,for循环:while循环加if.else以及elif,for循环嵌套for循环:break,终止循环,continue跳出循环:for i ...

  4. FFmpeg 常用命令收集

    FFmpeg 常用命令 合并视频 ffmpeg -i "KTDS-820A_FHD.mp4" -c copy -bsf:v h264_mp4toannexb -f mpegts i ...

  5. 【Alpha】第七次Daily Scrum Meeting

    GIT 一.今日站立式会议照片        二.会议内容 1.讨论送礼物的方法和对象,使功能更加完善. 2.对于程序还存在的问题提出自己的看法,尽量让功能更加的饱满. 三.燃尽图 四.遇到的困难 能 ...

  6. 201521123006 《Java程序设计》第3周学习总结

    本周学习总结 1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. ...

  7. 201521123035《Java程序设计》第十三周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...

  8. 201521123027 <java程序设计>第11周学习总结

    1.本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2.书面作业 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchro ...

  9. JAVA课程设计--------五子棋

    1.团队课程设计博客链接 http://www.cnblogs.com/mz201521044152/p/7065575.html 2.个人负责模块或任务说明 1.重新开始:写一个restartgam ...

  10. 关于centOS 7的服务启动,端口查询,防火墙管理

    端口的查询与开启 CentOS 7 默认没有使用iptables,所以通过编辑iptables的配置文件来开启80端口是不可以的CentOS 7 采用了 firewalld 防火墙 如要查询是否开启8 ...